#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# Copyright 2022 Huaqin Technology. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#    * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
#    * Neither the name of Huaqin Technology nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import subprocess
import argparse
import os
import time
import datetime
import threading
import re
import sys
import csv
import json
import pprint
import signal
import xml.etree.ElementTree as XMLET
import zipfile
import configparser

import map_analyzer.map_analyzer as map_analyzer

_TOOLS_PATH = os.getcwd() + '/'
_WORKING_ROOT_DIR = 'working/'
_WORKING_ROOT_PATH = os.getcwd() + '/' + _WORKING_ROOT_DIR

_PROJECT_LIST_tws_master_202208301600 = ["TS6569A", "TS6656A"]
_PROJECT_LIST_tws_ts6569a_202302141700 = ["TS6569A_STR4","TS6569A_X22E9"]
_PROJECT_LIST_tws_ts6566a_202307051530 = ["TS6656A_STR4","X23E6"]
_PROJECT_LIST_tws_ts6788a_202308281500 = ["TS6788A_STR4"]
_PROJECT_LIST_tws_pdp2313a_mr_20240621 = ["TS6788A_MR"]
_PROJECT_LIST_tws_ts6858a_202310231400 = ["TS6858A_TR5"]
_PROJECT_LIST_tws_ts6858s_202402071600 = ["TS6858S"]
_PROJECT_LIST_tws_hw_baseline = ["TS6858A", "TS6653A", "TS6351A", "TS6569A_HW_BASE"]
_PROJECT_LIST_tws_hw_bussiness_202304281700 = ["TS6653A_BUSSINESS"]
_PROJECT_LIST_hw_baseline_tag_before_202305172312 = ["TS6653A_TAG_BEFORE"]
_PROJECT_LIST_tws_ts6653a_tag260844_202306162000 = ["TS6653A_TAG_TR5_BACKUP"]
_PROJECT_LIST_tws_ts6653s_dev = ["TS6653S_DEV"]
_PROJECT_LIST_tws_ts6721a_dev_202303231126 = ["TS6721A"]
_PROJECT_LIST_tws_ts6721a_business_202306161200 = ["TS6721A_BUSSINESS"]
_PROJECT_LIST_tws_baseline = ["TS6721A","TS6569A", "TS6656A", "TS6788A","TS6788A_HW"]
_PROJECT_LIST_tws_ts6656a_spatial_audio_202306161730 = ["TS6656A_SPATIAL_AUDIO"]
_PROJECT_LIST_tws_TS6938A_202310091430 = ["TS6938A"]
_PROJECT_LIST_tws_TS6938A_mr_202404191900 = ["TS6938A_MR"]
_PROJECT_LIST_tws_TS6938A_bugfix_202405311050 = ["TS6938A_FIX"]
_PROJECT_LIST_tws_SS6950A_SS6950B_202309082200 = ["SS6950A","SS6950B"]
_PROJECT_LIST_tws_SS6950A_202312291700 = ["SS6950A_MR"]
_PROJECT_LIST_tws_SS6950B_202401241700 = ["SS6950B_MR"]
_PROJECT_LIST_tws_SS6950A_MR_TAG = ["SS6950A_MR_TAG"]
_PROJECT_LIST_tws_SS6950A_MR_TAG_0307 = ["SS6950A_MR_0307"]
_PROJECT_LIST_tws_SS6950B_MR_TAG = ["SS6950B_MR_TAG"]
_PROJECT_LIST_tws_SS6950B_MR_TAG_0307 = ["SS6950B_MR_0307"]
_PROJECT_LIST_tws_PA8414_202311071100 = ["PA8414_QCOM"]
_PROJECT_LIST_tws_PA8414_202312202000 = ["PA8414","TS7037A"]
_PROJECT_LIST_tws_ts6656a_shining_sword_202312081530 = ["TS6656A_SWORD"]
_PROJECT_LIST_tws_ts7252a_dev_202404251600 = ["TS7252A_DEV"]
_PROJECT_LIST_tws_xiapu_202407091430 = ["SHARP"]
_PROJECT_CONFIG_INFO = {
    # SHARP 夏普
    'SHARP' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/xiapu/tws_xiapu_202407091430.xml',
        'branch_revision': 'tws_xiapu_202407091430',
        'earphone_build_cmd': './build.sh sharp',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/sharp/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'sharp.bin',
                                            'sharp.elf',
                                            'sharp.lst',
                                            'sharp.map',
                                            '_sharp.bin_org'
                                            ],
        'img_file_dict': {'earbud': {'map': 'sharp.map',
                                       'bin': 'sharp.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_xiapu_202407091430,
        'twslint_version': 'v0.3',  # v0.3表示使用lintv0.3脚本(新的例外检查方式)，v0.2表示使用lintv0.2脚本(老的例外filter检查方式)
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'tws/xiapu/tws_xiapu_202407091430.xml'
    },
    # O71 TS7252A 主干分支
    'TS7252A_DEV': {
        'platform_type': 'qcom',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/O71/tws_o71_dev_202404251600.xml',
        'branch_revision': 'tws_o71_dev_202404251600',
        #'earphone_build_cmd': '/workdisk/dockers/scripts/docker_build.sh ts7252a',
        'earphone_build_cmd': './build.sh ts7252a all build',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'out/',
        'earphone_build_output_file_path': 'out/',
        'earphone_build_output_file_list': ['earbud.hex', 'earbud.elf', 'earbud.map', 'dfu_file.bin', 'sensor/app.elf'],
        'img_file_dict': {'earbud': {'map': 'earbud.map',
                                     'hex': 'earbud.hex'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone_v3', 'HQ_BD1SW_PA1952/earphone/platform/frameworks_v3', 'HQ_BD1SW_PA1952/earphone/platform/lal_v3'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone_v3', 'HQ_BD1SW_PA1952/earphone/platform/frameworks_v3','HQ_BD1SW_PA1952/earphone/platform/lal_v3'],
        'cppcheck_marco_def' : '-DUNITCODESECTION -DMARSHAL_COMMON_TYPES_TABLE -DLOGGING_PRESERVE_MESSAGE_ENUM',
        "impact_project_list": _PROJECT_LIST_tws_ts7252a_dev_202404251600,
        'twslint_version': 'v0.3',  # v0.3表示使用lintv0.3脚本(新的例外检查方式)，v0.2表示使用lintv0.2脚本(老的例外filter检查方式)
    },
    # OWS BES TS7037A 分支
    'TS7037A' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/PA8414/tws_master_202312081800.xml',
        'branch_revision': 'tws_master_202312081800',
        'earphone_build_cmd': './build.sh dora_zp_hq',
        'earphone_build_dir': 'build/',
        'earphone_build_test_file': 'build/build.sh',
        'earphone_build_output_path': 'out/',
        'earphone_build_output_file_path': 'out/target/product/dora_zp_hq/best1600_ibrt/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'best1600_ibrt.elf',
                                            'best1600_ibrt.map',
                                            'best1600_ibrt.bin',],
	'img_file_dict': {'earbud': {'map': 'best1600_ibrt.map',
                                       'bin': 'best1600_ibrt.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/apps_example','HQ_BD1SW_PA1952/earphone_v2_1'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/apps_example','HQ_BD1SW_PA1952/earphone_v2_1'],
        "impact_project_list": _PROJECT_LIST_tws_PA8414_202312202000,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # OWS BES PA8414 分支
    'PA8414' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/PA8414/tws_master_202312081800.xml',
        'branch_revision': 'tws_master_202312081800',
        'earphone_build_cmd': './build.sh',
        'earphone_build_dir': 'build/',
        'earphone_build_test_file': 'build/build.sh',
        'earphone_build_output_path': 'out/',
        'earphone_build_output_file_path': 'out/target/product/dora_hq/best1600_ibrt/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'best1600_ibrt.elf',
                                            'best1600_ibrt.map',
                                            'best1600_ibrt.bin',],
        'img_file_dict': {'earbud': {'map': 'best1600_ibrt.map',
                                       'bin': 'best1600_ibrt.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/apps_example','HQ_BD1SW_PA1952/earphone_v2_1'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/apps_example','HQ_BD1SW_PA1952/earphone_v2_1'],
        "impact_project_list": _PROJECT_LIST_tws_PA8414_202312202000,
        # 'twslint_version': 'v0.3',  # v0.3表示使用lintv0.3脚本(新的例外检查方式)，v0.2表示使用lintv0.2脚本(老的例外filter检查方式)
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },

    # OWS PA8414_OLD 分支
    'PA8414_QCOM' : {
        'platform_type': 'qcom',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/PA8414/tws_pa8414_dev_202310301400.xml',
        'branch_revision': 'tws_qcom_master_202310301400',
        'earphone_build_cmd': './build.sh',
        'earphone_build_dir': 'qcc518x_qcc308x_20231030/',
        'earphone_build_test_file': 'qcc518x_qcc308x_20231030/build.sh',
        'earphone_build_output_path': 'qcc518x_qcc308x_20231030/out/',
        'earphone_build_output_file_path': 'qcc518x_qcc308x_20231030/out/target/product/dora_hq/',
        'earphone_build_output_file_list': ['flash_image.xuv',
                                            'earbud.elf',
                                            'earbud.map',],
        'img_file_dict': {'earbud': {'map': 'earbud.map'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_PA8414_202311071100,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # N75 TS6938A 分支
    'TS6938A' : {
        'platform_type': 'qcom',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/TS6938A/tws_ts6938a_dev_202309051100.xml',
        'branch_revision': 'tws_qcom_master_202309051100',
        'earphone_build_cmd': './build.sh',
        'earphone_build_dir': 'qcc518x_qcc308x_20230905/',
        'earphone_build_test_file': 'qcc518x_qcc308x_20230905/build.sh',
        'earphone_build_output_path': 'qcc518x_qcc308x_20230905/out/',
        'earphone_build_output_file_path': 'qcc518x_qcc308x_20230905/out/target/product/TS6938A/',
        'earphone_build_output_file_list': ['flash_image.xuv',
                                            'earbud.elf',
                                            'earbud.map',],
        'img_file_dict': {'earbud': {'map': 'earbud.map'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone_v2'],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_TS6938A_202310091430,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # N75 TS6938A 商用分支
    'TS6938A_MR' : {
        'platform_type': 'qcom',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/TS6938A/tws_ts6938a_mr_202404191900.xml',
        'branch_revision': 'tws_ts6938a_mr_202404191900',
        'earphone_build_cmd': './build.sh',
        'earphone_build_dir': 'qcc518x_qcc308x_20230905/',
        'earphone_build_test_file': 'qcc518x_qcc308x_20230905/build.sh',
        'earphone_build_output_path': 'qcc518x_qcc308x_20230905/out/',
        'earphone_build_output_file_path': 'qcc518x_qcc308x_20230905/out/target/product/TS6938A/',
        'earphone_build_output_file_list': ['flash_image.xuv',
                                            'earbud.elf',
                                            'earbud.map',],
        'img_file_dict': {'earbud': {'map': 'earbud.map'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone_v2'],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_TS6938A_mr_202404191900,
    },
    # N75 TS6938A BUGFIX分支
    'TS6938A_FIX' : {
        'platform_type': 'qcom',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/TS6938A/tws_ts6938a_bugfix_202405311050.xml',
        'branch_revision': 'tws_ts6938a_bugfix_202405311050',
        'earphone_build_cmd': './build.sh',
        'earphone_build_dir': 'qcc518x_qcc308x_20230905/',
        'earphone_build_test_file': 'qcc518x_qcc308x_20230905/build.sh',
        'earphone_build_output_path': 'qcc518x_qcc308x_20230905/out/',
        'earphone_build_output_file_path': 'qcc518x_qcc308x_20230905/out/target/product/TS6938A/',
        'earphone_build_output_file_list': ['flash_image.xuv',
                                            'earbud.elf',
                                            'earbud.map',],
        'img_file_dict': {'earbud': {'map': 'earbud.map'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone_v2'],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_TS6938A_bugfix_202405311050,
    },
    #SS6950B 商用分支
    'SS6950B_MR' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/M1_Audio/tws_m2_audio_business_202401241700.xml',
        'branch_revision': 'tws_m2_audio_business_202401241700',
        'earphone_build_cmd': './build.sh M02A',
        'earphone_build_dir': 'rainbow_jbl_baseline/jbl/',
        'earphone_build_test_file': 'rainbow_jbl_baseline/jbl/build.sh',
        'earphone_build_output_path': 'rainbow_jbl_baseline/jbl/out/',
        'earphone_build_output_file_path': 'rainbow_jbl_baseline/jbl/out/M02A/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'M02A.bin',
                                            'M02A.elf',
                                            'M02A.map',],
        'img_file_dict': {'earbud': {'map': 'M02A.map',
                                       'bin': 'M02A.bin'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_SS6950B_202401241700,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    #SS6950A 商用分支
    'SS6950A_MR' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/M1_Audio/tws_m1_audio_business_202312291700.xml',
        'branch_revision': 'tws_m1_audio_business_202312291700',
        'earphone_build_cmd': './build.sh M01A',
        'earphone_build_dir': 'rainbow_jbl_baseline/jbl/',
        'earphone_build_test_file': 'rainbow_jbl_baseline/jbl/build.sh',
        'earphone_build_output_path': 'rainbow_jbl_baseline/jbl/out/',
        'earphone_build_output_file_path': 'rainbow_jbl_baseline/jbl/out/M01A/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'M01A.bin',
                                            'M01A.elf',
                                            'M01A.map',],
        'img_file_dict': {'earbud': {'map': 'M01A.map',
                                       'bin': 'M01A.bin'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_SS6950A_202312291700,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    #SS6950B TAG 0307分支
    'SS6950B_MR_0307' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/M1_Audio/tws_m2_tag_bd1swscm23_202403071330.xml',
        'branch_revision': 'tws_m2_tag_bd1swscm23_202403071330',
        'earphone_build_cmd': './build.sh M02A',
        'earphone_build_dir': 'rainbow_jbl_baseline/jbl/',
        'earphone_build_test_file': 'rainbow_jbl_baseline/jbl/build.sh',
        'earphone_build_output_path': 'rainbow_jbl_baseline/jbl/out/',
        'earphone_build_output_file_path': 'rainbow_jbl_baseline/jbl/out/M02A/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'M02A.bin',
                                            'M02A.elf',
                                            'M02A.map',],
        'img_file_dict': {'earbud': {'map': 'M02A.map',
                                       'bin': 'M02A.bin'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_SS6950B_MR_TAG_0307,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    #SS6950B TAG分支
    'SS6950B_MR_TAG' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/M1_Audio/tws_m2_tag_bd1swscm23_202403061100.xml',
        'branch_revision': 'tws_m2_tag_bd1swscm23_202403061100',
        'earphone_build_cmd': './build.sh M02A',
        'earphone_build_dir': 'rainbow_jbl_baseline/jbl/',
        'earphone_build_test_file': 'rainbow_jbl_baseline/jbl/build.sh',
        'earphone_build_output_path': 'rainbow_jbl_baseline/jbl/out/',
        'earphone_build_output_file_path': 'rainbow_jbl_baseline/jbl/out/M02A/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'M02A.bin',
                                            'M02A.elf',
                                            'M02A.map',],
        'img_file_dict': {'earbud': {'map': 'M02A.map',
                                       'bin': 'M02A.bin'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_SS6950B_MR_TAG,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    #SS6950A TAG 0307分支
    'SS6950A_MR_0307' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/M1_Audio/tws_m1_tag_bd1swscm23_202403071330.xml',
        'branch_revision': 'tws_m1_tag_bd1swscm23_202403071330',
        'earphone_build_cmd': './build.sh M01A',
        'earphone_build_dir': 'rainbow_jbl_baseline/jbl/',
        'earphone_build_test_file': 'rainbow_jbl_baseline/jbl/build.sh',
        'earphone_build_output_path': 'rainbow_jbl_baseline/jbl/out/',
        'earphone_build_output_file_path': 'rainbow_jbl_baseline/jbl/out/M01A/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'M01A.bin',
                                            'M01A.elf',
                                            'M01A.map',],
        'img_file_dict': {'earbud': {'map': 'M01A.map',
                                       'bin': 'M01A.bin'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_SS6950A_MR_TAG_0307,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },

    #SS6950A TAG分支
    'SS6950A_MR_TAG' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/M1_Audio/tws_m1_tag_bd1swscm23_202403061100.xml',
        'branch_revision': 'tws_m1_tag_bd1swscm23_202403061100',
        'earphone_build_cmd': './build.sh M01A',
        'earphone_build_dir': 'rainbow_jbl_baseline/jbl/',
        'earphone_build_test_file': 'rainbow_jbl_baseline/jbl/build.sh',
        'earphone_build_output_path': 'rainbow_jbl_baseline/jbl/out/',
        'earphone_build_output_file_path': 'rainbow_jbl_baseline/jbl/out/M01A/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'M01A.bin',
                                            'M01A.elf',
                                            'M01A.map',],
        'img_file_dict': {'earbud': {'map': 'M01A.map',
                                       'bin': 'M01A.bin'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_SS6950A_MR_TAG,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # 小米音响 SS6950A_SS6950B 分支
    'SS6950A' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/M1_Audio/tws_m1_audio_202309072030.xml',
        'branch_revision': 'tws_m1_audio_202309072030',
        'earphone_build_cmd': './build.sh M01A',
        'earphone_build_dir': 'rainbow_jbl_baseline/jbl/',
        'earphone_build_test_file': 'rainbow_jbl_baseline/jbl/build.sh',
        'earphone_build_output_path': 'rainbow_jbl_baseline/jbl/out/',
        'earphone_build_output_file_path': 'rainbow_jbl_baseline/jbl/out/M01A/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'M01A.bin',
                                            'M01A.elf',
                                            'M01A.map',],
        'img_file_dict': {'earbud': {'map': 'M01A.map',
                                       'bin': 'M01A.bin'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_SS6950A_SS6950B_202309082200,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    'SS6950B' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/M1_Audio/tws_m1_audio_202309072030.xml',
        'branch_revision': 'tws_m1_audio_202309072030',
        'earphone_build_cmd': './build.sh M02A',
        'earphone_build_dir': 'rainbow_jbl_baseline/jbl/',
        'earphone_build_test_file': 'rainbow_jbl_baseline/jbl/build.sh',
        'earphone_build_output_path': 'rainbow_jbl_baseline/jbl/out/',
        'earphone_build_output_file_path': 'rainbow_jbl_baseline/jbl/out/M02A/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'M02A.bin',
                                            'M02A.elf',
                                            'M02A.map',],
        'img_file_dict': {'earbud': {'map': 'M02A.map',
                                       'bin': 'M02A.bin'}},
        'twslint_project': [''],
        'cppcheck_project': [''],
        "impact_project_list": _PROJECT_LIST_tws_SS6950A_SS6950B_202309082200,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # 柯西
    'TS6569A' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/base/tws_baseline.xml',
        'branch_revision': 'tws_master_202208301600',
        'earphone_build_cmd': './build.sh ts6569a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6569a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6569a.bin',
                                            'ts6569a.elf',
                                            'ts6569a.lst',
                                            'ts6569a.map',
                                            'ts6569a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6569a.map',
                                       'bin': 'ts6569a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_baseline,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # 柯西 STR4A分支
    'TS6569A_STR4' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_ts6569a_202302141700.xml',
        'branch_revision': 'tws_ts6569a_202302141700',
        'earphone_build_cmd': './build.sh ts6569a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6569a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6569a.bin',
                                            'ts6569a.elf',
                                            'ts6569a.lst',
                                            'ts6569a.map',
                                            'ts6569a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6569a.map',
                                       'bin': 'ts6569a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6569a_202302141700,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # 柯西 X22E9分支
    'TS6569A_X22E9' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_ts6569a_202302141700.xml',
        'branch_revision': 'tws_ts6569a_202302141700',
        'earphone_build_cmd': './build.sh X22E9',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/X22E9/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'X22E9.bin',
                                            'X22E9.elf',
                                            'X22E9.lst',
                                            'X22E9.map',
                                            'X22E9.str'],
        'img_file_dict': {'earbud': {'map': 'X22E9.map',
                                       'bin': 'X22E9.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6569a_202302141700,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # 柯西hw_base分支
    'TS6569A_HW_BASE' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_hw_baseline.xml',
        'branch_revision': 'tws_hw_baseline_202301041100',
        'earphone_build_cmd': './build.sh ts6569a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6569a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6569a.bin',
                                            'ts6569a.elf',
                                            'ts6569a.lst',
                                            'ts6569a.map',
                                            'ts6569a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6569a.map',
                                       'bin': 'ts6569a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_hw_baseline,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
        "check_safe_function": False
    },
    # 天燕
    'TS6656A' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/base/tws_baseline.xml',
        'branch_revision': 'tws_master_202208301600',
        'earphone_build_cmd': './build.sh ts6656a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6656a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6656a.bin',
                                            'ts6656a.elf',
                                            'ts6656a.lst',
                                            'ts6656a.map',
                                            'ts6656a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6656a.map',
                                       'bin': 'ts6656a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_baseline,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # 天燕 STR4
    'TS6656A_STR4' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_ts6656a_str4_202307051530.xml',
        'branch_revision': 'tws_ts6656a_str4_202307051530',
        'earphone_build_cmd': './build.sh ts6656a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6656a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6656a.bin',
                                            'ts6656a.elf',
                                            'ts6656a.lst',
                                            'ts6656a.map',
                                            'ts6656a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6656a.map',
                                       'bin': 'ts6656a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6566a_202307051530,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # X236E
    'X23E6' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_ts6656a_str4_202307051530.xml',
        'branch_revision': 'tws_ts6656a_str4_202307051530',
        'earphone_build_cmd': './build.sh X23E6',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/X23E6/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'X23E6.bin',
                                            'X23E6.elf',
                                            'X23E6.lst',
                                            'X23E6.map',
                                            'X23E6.str'],
        'img_file_dict': {'earbud': {'map': 'X23E6.map',
                                       'bin': 'X23E6.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6566a_202307051530,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # 天燕 SWORD
    'TS6656A_SWORD' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/TS6656A/tws_ts6656a_shining_sword_202312081530.xml',
        'branch_revision': 'tws_ts6656a_shining_sword_202312081530',
        'earphone_build_cmd': './build.sh ts6656a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6656a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6656a.bin',
                                            'ts6656a.elf',
                                            'ts6656a.lst',
                                            'ts6656a.map',
                                            'ts6656a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6656a.map',
                                       'bin': 'ts6656a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6656a_shining_sword_202312081530,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },


    # 天燕 spatial_audio
    'TS6656A_SPATIAL_AUDIO' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_ts6656a_spatial_audio_202306161730.xml',
        'branch_revision': 'tws_ts6656a_spatial_audio_202306161730',
        'earphone_build_cmd': './build.sh ts6656a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6656a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6656a.bin',
                                            'ts6656a.elf',
                                            'ts6656a.lst',
                                            'ts6656a.map',
                                            'ts6656a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6656a.map',
                                       'bin': 'ts6656a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6656a_spatial_audio_202306161730,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # 荣耀
    'TS6858A' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_hw_baseline.xml',
        'branch_revision': 'tws_hw_baseline_202301041100',
        'earphone_build_cmd': './build.sh ts6858a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6858a/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_2_0_slink-ts6858a-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
	"impact_project_list": _PROJECT_LIST_tws_hw_baseline,
        "check_safe_function": True
    },

    # 荣耀
    'TS6858A_TR5' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/TS6858A/TS6858A_tws_peter_20231023.xml',
        'branch_revision': 'TS6858A_tws_peter_20231023',
        'earphone_build_cmd': './build.sh ts6858a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6858a/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_2_0_slink-ts6858a-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6858a_202310231400,
        "check_safe_function": True
    },
    # 荣耀 PeterR TS6858S 
    'TS6858S' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/TS6858S/tws_peter_r_202402071600.xml',
        'branch_revision': 'tws_peter_r_202402071600',
        'earphone_build_cmd': './build.sh ts6858s',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6858s/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_2_0_slink-ts6858s-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6858s_202402071600,
        "check_safe_function": True
    },
    # ULC+
    'TS6653S_DEV' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_hw_baseline_202301041100.xml',
        'branch_revision': 'tws_hw_baseline_202301041100',
        'earphone_build_cmd': './build.sh ts6653s',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6653s/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_2_0_slink-ts6653s-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6653s_dev,
        "check_safe_function": True
    },
    # ULC
    'TS6653A' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_hw_baseline.xml',
        'branch_revision': 'tws_hw_baseline_202301041100',
        'earphone_build_cmd': './build.sh ts6653a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6653a/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_2_0_slink-ts6653a-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_hw_baseline,
        "check_safe_function": True
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_hw_baseline_202301041100.xml'
    },

    # ULC - tws_hw_bussiness_202304281700
    'TS6653A_BUSSINESS' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_hw_bussiness_202304281700.xml',
        'branch_revision': 'tws_hw_bussiness_202304281700',
        'earphone_build_cmd': './build.sh ts6653a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6653a/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_2_0_slink-ts6653a-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_hw_bussiness_202304281700,
        "check_safe_function": True
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_hw_baseline_202301041100.xml'
    },
    # ULC - hw_baseline_tag_before_202305172312
    'TS6653A_TAG_BEFORE' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/hw_baseline_tag_before_202305172312.xml',
        'branch_revision': 'hw_baseline_tag_before_202305172312',
        'earphone_build_cmd': './build.sh ts6653a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6653a/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_2_0_slink-ts6653a-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_hw_baseline_tag_before_202305172312,
        "check_safe_function": True
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_hw_baseline_202301041100.xml'
    },

    # ULC - tws_ts6653a_tag260844_202306162000
    'TS6653A_TAG_TR5_BACKUP' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_ts6653a_tag260844_202306162000.xml',
        'branch_revision': 'tws_ts6653a_tag260844_202306162000',
        'earphone_build_cmd': './build.sh ts6653a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6653a/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_2_0_slink-ts6653a-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6653a_tag260844_202306162000,
        "check_safe_function": True
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_hw_baseline_202301041100.xml'
    },
    # T300
    'TS6721A' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/base/tws_baseline.xml',
        'branch_revision': 'tws_master_202208301600',
        'earphone_build_cmd': './build.sh ts6721a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6721a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6721a.bin',
                                            'ts6721a.elf',
                                            'ts6721a.lst',
                                            'ts6721a.map',
                                            'ts6721a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6721a.map',
                                       'bin': 'ts6721a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_baseline,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    # T300
    'TS6721A_BUSSINESS' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_ts6721a_business_202306161200.xml',
        'branch_revision': 'tws_ts6721a_business_202306161200',
        'earphone_build_cmd': './build.sh ts6721a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6721a/user/',
        'earphone_build_output_file_list': ['_best1000.lds',
                                            'ts6721a.bin',
                                            'ts6721a.elf',
                                            'ts6721a.lst',
                                            'ts6721a.map',
                                            'ts6721a.str'],
        'img_file_dict': {'earbud': {'map': 'ts6721a.map',
                                       'bin': 'ts6721a.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6721a_business_202306161200,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
    #金牛
    'TS6351A' : {
        'platform_type': 'wq',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'BD1SW/tws_hw_baseline.xml',
        'branch_revision': 'tws_hw_baseline_202301041100',
        'earphone_build_cmd': './build.sh ts6351a',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/ts6351a/bin/',
        'earphone_build_output_file_list': ["tws_core0.asm",
                                            "tws_core0.txt",
                                            "link.lds",
                                            "tws_core0.bin",
                                            "tws_core0.info",
                                            "log_table.txt",
                                            "dbglog_table.txt",
                                            "tws_core0.log",
                                            "memory_config.json",
                                            "tws_core0.elf",
                                            "tws_core0.map",
                                            "../package/*.wpk"],
        'img_file_dict': {'earbud': {'map': 'tws_core0.map',
                                       'bin': 'tws_core0.bin',
                                       'layout': 'memory_config.json',
                                       "pkg": "patch_tws_1_1_4m-ts6351a-0.0.0.0_offline_log.wpk"}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_hw_baseline,
        "check_safe_function": False
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_hw_baseline_202301041100.xml'
    },

    # TS6788A vivo MR猫王
    'TS6788A_MR' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/DPD2313A/tws_pdp2313a_mr_20240621.xml',
        'branch_revision': 'tws_pdp2313a_mr_20240621',
        'earphone_build_cmd': './build.sh DPD2313A && ./build.sh DPD2313A_boot',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/DPD2313A/user/',
        'earphone_build_output_file_list': ['_best1000_1306.lds',
                                            'DPD2313A.bin',
                                            'DPD2313A.elf',
                                            'DPD2313A.lst',
                                            'DPD2313A.map',
                                            'DPD2313A.str'
                                            ],
        'img_file_dict': {'earbud': {'map': 'DPD2313A.map',
                                       'bin': 'DPD2313A.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone_v2','HQ_BD1SW_PA1952/earphone/app/green','HQ_BD1SW_PA1952/earphone/app/blue','HQ_BD1SW_PA1952/earphone/build/bes','HQ_BD1SW_PA1952/earphone/build/bes_v2','HQ_BD1SW_PA1952/earphone/build/wq','HQ_BD1SW_PA1952/earphone/device/bt/blue','HQ_BD1SW_PA1952/earphone/device/bt/green','HQ_BD1SW_PA1952/earphone/platform/frameworks','HQ_BD1SW_PA1952/earphone/platform/lal','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A','HQ_BD1SW_PA1952/earphone/product/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone_v2','HQ_BD1SW_PA1952/earphone/app/green','HQ_BD1SW_PA1952/earphone/app/blue','HQ_BD1SW_PA1952/earphone/build/bes','HQ_BD1SW_PA1952/earphone/build/bes_v2','HQ_BD1SW_PA1952/earphone/build/wq','HQ_BD1SW_PA1952/earphone/device/bt/blue','HQ_BD1SW_PA1952/earphone/device/bt/green','HQ_BD1SW_PA1952/earphone/platform/frameworks','HQ_BD1SW_PA1952/earphone/platform/lal','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A','HQ_BD1SW_PA1952/earphone/product/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_pdp2313a_mr_20240621,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },

    # TS6788A vivo猫王
    'TS6788A_STR4' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/DPD2313A/tws_dpd2313a_tr4_202308281500.xml',
        'branch_revision': 'tws_ts6788a_tr4_202308281500',
        'earphone_build_cmd': './build.sh DPD2313A && ./build.sh DPD2313A_boot',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/DPD2313A/user/',
        'earphone_build_output_file_list': ['_best1000_1306.lds',
                                            'DPD2313A.bin',
                                            'DPD2313A.elf',
                                            'DPD2313A.lst',
                                            'DPD2313A.map',
                                            'DPD2313A.str'
                                            ],
        'img_file_dict': {'earbud': {'map': 'DPD2313A.map',
                                       'bin': 'DPD2313A.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone_v2','HQ_BD1SW_PA1952/earphone/app/green','HQ_BD1SW_PA1952/earphone/app/blue','HQ_BD1SW_PA1952/earphone/build/bes','HQ_BD1SW_PA1952/earphone/build/bes_v2','HQ_BD1SW_PA1952/earphone/build/wq','HQ_BD1SW_PA1952/earphone/device/bt/blue','HQ_BD1SW_PA1952/earphone/device/bt/green','HQ_BD1SW_PA1952/earphone/platform/frameworks','HQ_BD1SW_PA1952/earphone/platform/lal','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A','HQ_BD1SW_PA1952/earphone/product/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone_v2','HQ_BD1SW_PA1952/earphone/app/green','HQ_BD1SW_PA1952/earphone/app/blue','HQ_BD1SW_PA1952/earphone/build/bes','HQ_BD1SW_PA1952/earphone/build/bes_v2','HQ_BD1SW_PA1952/earphone/build/wq','HQ_BD1SW_PA1952/earphone/device/bt/blue','HQ_BD1SW_PA1952/earphone/device/bt/green','HQ_BD1SW_PA1952/earphone/platform/frameworks','HQ_BD1SW_PA1952/earphone/platform/lal','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A','HQ_BD1SW_PA1952/earphone/product/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_ts6788a_202308281500,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },

    # TS6788A vivo猫王
    'TS6788A' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/base/tws_baseline.xml',
        'branch_revision': 'tws_master_202208301600',
        'earphone_build_cmd': './build.sh DPD2313A && ./build.sh DPD2313A_boot',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/DPD2313A/user/',
        'earphone_build_output_file_list': ['_best1000_1306.lds',
                                            'DPD2313A.bin',
                                            'DPD2313A.elf',
                                            'DPD2313A.lst',
                                            'DPD2313A.map',
                                            'DPD2313A.str'
                                            ],
        'img_file_dict': {'earbud': {'map': 'DPD2313A.map',
                                       'bin': 'DPD2313A.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone_v2','HQ_BD1SW_PA1952/earphone/app/green','HQ_BD1SW_PA1952/earphone/app/blue','HQ_BD1SW_PA1952/earphone/build/bes','HQ_BD1SW_PA1952/earphone/build/bes_v2','HQ_BD1SW_PA1952/earphone/build/wq','HQ_BD1SW_PA1952/earphone/device/bt/blue','HQ_BD1SW_PA1952/earphone/device/bt/green','HQ_BD1SW_PA1952/earphone/platform/frameworks','HQ_BD1SW_PA1952/earphone/platform/lal','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A','HQ_BD1SW_PA1952/earphone/product/earphone'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone_v2','HQ_BD1SW_PA1952/earphone/app/green','HQ_BD1SW_PA1952/earphone/app/blue','HQ_BD1SW_PA1952/earphone/build/bes','HQ_BD1SW_PA1952/earphone/build/bes_v2','HQ_BD1SW_PA1952/earphone/build/wq','HQ_BD1SW_PA1952/earphone/device/bt/blue','HQ_BD1SW_PA1952/earphone/device/bt/green','HQ_BD1SW_PA1952/earphone/platform/frameworks','HQ_BD1SW_PA1952/earphone/platform/lal','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A','HQ_BD1SW_PA1952/earphone/product/earphone'],
        "impact_project_list": _PROJECT_LIST_tws_baseline,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },

# TS6788A vivo猫王海外版
    'TS6788A_HW' : {
        'platform_type': 'bes',
        'code_server': 'gerrit.huaqin.com',
        'code_server_port': '29418',
        'cherrypick_server': 'gerrit.huaqin.com',
        'cherrypick_server_port': '29418',
        'review_server': 'gerrit.huaqin.com',
        'review_server_port': '29418',
        'manifest': 'tws/base/tws_baseline.xml',
        'branch_revision': 'tws_master_202208301600',
        'earphone_build_cmd': './build.sh DPD2313A_hw && ./build.sh DPD2313A_hw_boot',
        'earphone_build_dir': 'earphone/',
        'earphone_build_test_file': 'earphone/build.sh',
        'earphone_build_output_path': 'earphone/out/',
        'earphone_build_output_file_path': 'earphone/out/DPD2313A_hw/user/',
        'earphone_build_output_file_list': ['_best1000_1306.lds',
                                            'DPD2313A_hw.bin',
                                            'DPD2313A_hw.elf',
                                            'DPD2313A_hw.lst',
                                            'DPD2313A_hw.map',
                                            'DPD2313A_hw.str'
                                            ],
        'img_file_dict': {'earbud': {'map': 'DPD2313A_hw.map',
                                       'bin': 'DPD2313A_hw.bin'}},
        'twslint_project': ['HQ_BD1SW_PA1952/earphone_v2','HQ_BD1SW_PA1952/earphone/app/green','HQ_BD1SW_PA1952/earphone/app/blue','HQ_BD1SW_PA1952/earphone/build/bes','HQ_BD1SW_PA1952/earphone/build/bes_v2','HQ_BD1SW_PA1952/earphone/build/wq','HQ_BD1SW_PA1952/earphone/device/bt/blue','HQ_BD1SW_PA1952/earphone/device/bt/green','HQ_BD1SW_PA1952/earphone/platform/frameworks','HQ_BD1SW_PA1952/earphone/platform/lal','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A','HQ_BD1SW_PA1952/earphone/product/earphone','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A_hw'],
        'cppcheck_project': ['HQ_BD1SW_PA1952/earphone_v2','HQ_BD1SW_PA1952/earphone/app/green','HQ_BD1SW_PA1952/earphone/app/blue','HQ_BD1SW_PA1952/earphone/build/bes','HQ_BD1SW_PA1952/earphone/build/bes_v2','HQ_BD1SW_PA1952/earphone/build/wq','HQ_BD1SW_PA1952/earphone/device/bt/blue','HQ_BD1SW_PA1952/earphone/device/bt/green','HQ_BD1SW_PA1952/earphone/platform/frameworks','HQ_BD1SW_PA1952/earphone/platform/lal','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A','HQ_BD1SW_PA1952/earphone/product/earphone','HQ_BD1SW_PA1952/earphone/product/earphone/DPD2313A_hw'],
        "impact_project_list": _PROJECT_LIST_tws_baseline,
        # 'res_check_project': {'HQ_BD1SW_PA1952/earphone'},
        # 'xml': 'BD1SW/tws_master_202208301600.xml'
    },
}
# account_id, code_server, code_server_port, manifest
_CODE_PULL_CMD_TEMPLATE = 'repo init --no-repo-verify -u ssh://%s@%s:%s/manifest -m %s  --depth=100 && repo sync -j4 -c --no-tags && repo start dev --all'

# account_id, cherrypick_server, cherrypick_server_port, _gerrit_project, _gerrit_ref_info
# _CHERRYPICK_CMD_TEMPLATE = 'git fetch ssh://101002563@gerrit.huaqin.com:29418/HQ_BD1SW_PA1952/earphone refs/changes/78/256878/1 && git cherry-pick FETCH_HEAD'
_CHERRYPICK_CMD_TEMPLATE = 'git clean -df .; git checkout -f .; git fetch ssh://%s@%s:%s/%s %s && git cherry-pick FETCH_HEAD'

# review_server_port, account_id, review_server, review_message, num, patchset
# ssh -p 29418 101002563@gerrit.huaqin.com gerrit review -m \"Build Successful.\" 256901,2
_GERRIT_REVIEW_CMD_TEMPLATE = 'ssh -p %s %s@%s gerrit review -m %s %s,%s'

LEVEL_ERROR = '[Error]'
LEVEL_INFO = '[Info]'
LEVEL_WARN = '[Warning]'

_LOG_ENV_WORKING_DIR = ''
_LOG_ENV_CODE_DIR = ''
_LOG_ENV_GUARD_INFO_HANDLE = None
def _LogInit(workdir='', codedir='', guard_info_handle=None):
    global _LOG_ENV_WORKING_DIR
    global _LOG_ENV_CODE_DIR
    global _LOG_ENV_GUARD_INFO_HANDLE
    if workdir:
        _LOG_ENV_WORKING_DIR = workdir
    if codedir:
        _LOG_ENV_CODE_DIR = codedir
    if guard_info_handle:
        _LOG_ENV_GUARD_INFO_HANDLE = guard_info_handle
    return


def LOG(level, msg):
    def time_str():
        return time.strftime('%Y-%m-%d %H:%M:%S  ', time.localtime())
    log_msg = time_str() + level + ': ' + str(msg)
    print(log_msg, flush=True)
    if level == LEVEL_ERROR:
        if os.path.exists(_LOG_ENV_CODE_DIR):
            cmd = 'rm -rf %s' % (_LOG_ENV_CODE_DIR)
            # subprocess.run(cmd, shell=True, timeout=120, encoding='utf8')
            TIMEOUT_SHELL_COMMAND(cmd, timeout=120)

        if _LOG_ENV_GUARD_INFO_HANDLE:
            port = _PROJECT_CONFIG_INFO.get(_LOG_ENV_GUARD_INFO_HANDLE._project_name).get('review_server_port')
            account = _LOG_ENV_GUARD_INFO_HANDLE.account_id
            server = _PROJECT_CONFIG_INFO.get(_LOG_ENV_GUARD_INFO_HANDLE._project_name).get('review_server')
            msg = '[TWS_GUARD] ' + "Review ***FAIL*** at {}\\\n\\\r".format(_LOG_ENV_GUARD_INFO_HANDLE.jenkins_url)
            for index in range(0, _LOG_ENV_GUARD_INFO_HANDLE._gerrit_project_count):
                change_num = _LOG_ENV_GUARD_INFO_HANDLE._gerrit_number[index]
                patch_set = _LOG_ENV_GUARD_INFO_HANDLE._gerrit_patchset_num[index]
                cmd = _GERRIT_REVIEW_CMD_TEMPLATE % (port,
                                                     account,
                                                     server,
                                                     "\\\'" + msg + "\\\'",
                                                     change_num,
                                                     patch_set) + " --verified -1"
                TIMEOUT_SHELL_COMMAND(cmd, timeout=60)
        exit(1)

import select
import pty
_SUBPROCESS_POPEN_POLL = True
def TIMEOUT_SHELL_COMMAND(command:str, timeout=60, capture_output=False, encoding ='utf8', cwd=None) -> list:
    if _SUBPROCESS_POPEN_POLL: # subprocess.Popen + poll方式
        def read(fd):
            try:
                return os.read(fd,1024).decode('utf-8', errors='replace')
            except OSError as e:
                if e.errno==5: # 输入输出错误
                    return
                else:
                    raise

        env = os.environ.copy()
        env['GIT_FLUSH'] = '1'

        cmd = command
        LOG(LEVEL_INFO, 'Popen_poll:CMD START: [cmd={}] [timeout={}] [capture_out={}] [encoding={}] [cwd={}]'.format(
            cmd, timeout, capture_output, encoding, cwd))

        #创建伪终端
        master_fd, slave_fd = pty.openpty()
        process = subprocess.Popen(cmd,
                                   shell=True,
                                   stdin=slave_fd,
                                   stdout=slave_fd, stderr=slave_fd, close_fds=True,
                                   env=env,
                                   encoding=encoding,
                                   cwd=cwd)

        #关闭slave文件描述符，因为我们只需要master描述符来读取输出
        os.close(slave_fd)

        def kill_process(p):
            p.kill()

        timer = threading.Timer(timeout, kill_process, [process])
        try:
            timer.start()

            stdout_output = ''
            while True:
                reads, _, _ = select.select([master_fd],[],[])
                for r in reads:
                    if r == master_fd:
                        output = read(master_fd)
                        if output:
                            stdout_output += output
                            print(output, flush=True, end="")

                #检查子进程是否结束
                if process.poll() is not None:
                    break

            #确保读取所有剩余的输出
            while True:
                output = read(master_fd)
                if not output:
                    break
                stdout_output += output
                print(output, end="")
        finally:
            #关闭master文件描述符
            os.close(master_fd)
            timer.cancel()

        LOG(LEVEL_INFO, 'Popen_poll:CMD END: [returncode={}]'.format(process.returncode))
        if stdout_output:
            if (not process.returncode):
                return [process.returncode, stdout_output.strip().split('\n')]
            else:
                return [process.returncode, []]
        else:
            return [process.returncode, []]
    else: # subprocess.run 方式
        cmd = command
        LOG(LEVEL_INFO, 'run:CMD START: [cmd={}] [timeout={}] [capture_out={}] [encoding={}] [cwd={}]'.format(
            cmd, timeout, capture_output, encoding, cwd))

        process = subprocess.run(cmd,
                                shell=True,
                                timeout=timeout,
                                capture_output=capture_output,
                                encoding=encoding,
                                cwd=cwd)
        LOG(LEVEL_INFO, 'CMD END: [returncode={}]'.format(process.returncode))
        if process.stdout:
            # LOG(LEVEL_INFO, 'CMD stdout = [{}]'.format(process.stdout))
            # if process.stderr:
            #   LOG(LEVEL_INFO, 'CMD stderr = [{}]'.format(process.stderr))
            if (not process.returncode):
                return [process.returncode, process.stdout.strip().split('\n')]
        else:
            return [process.returncode, []]

class _GuardInfo(object):
    def __init__(self) -> None:
        self.account_id = ''
        self.change_id = ''
        self.output_type = ''
        self.org_gerrit_data = []
        self._gerrit_project = []
        self._gerrit_project_count = 0
        self._gerrit_branch = ''
        self._gerrit_number = []
        self._gerrit_url = []
        self._gerrit_patchset_num = []
        self._gerrit_ref_info = []
        self._project_name = ''
        self._gerrit_file_list = []
        self._working_dir = ''
        self._code_root_path = ''
        self._manifest_project_path_dict = []
        self._cherrypick_cmd_list = []
        self._copied_image_path = {
            'earbud': {'root': 'earbud_img', 'org': 'earbud_img/org/', 'patch': 'earbud_img/patch/'},
            'box' : {'root': 'box_img', 'org': 'box_img/org/', 'patch': 'box_img/patch'},
        }
        self.jenkins_url = ''
        self.tws_lint_success = False
        self.cppcheck_success = False
        self.impact_build_success = False

    def _SetGerritProjectCount(self, count):
        self._gerrit_project_count = count

    def GetGerritProjectCount(self):
        return self._gerrit_project_count

    def _SetGerritProjectInfo(self, proj):
        """
        'project': 'HQ_BD1SW_PA1952/earphone'
        """
        self._gerrit_project.append(proj)
        self._SetGerritProjectCount(len(self._gerrit_project))

    def GetGerritProjectInfo(self, index):
        """
        example: 'project': 'HQ_BD1SW_PA1952/earphone'
        """
        if index >= len(self._gerrit_project):
            LOG(LEVEL_ERROR, 'The count of the Gerrit Project is [{}], but you set index [{}]'.format(
                len(self._gerrit_project), index))
        return self._gerrit_project[index]

    def _SetGerritBranchInfo(self, info):
        """
        example: 'branch': 'tws_master_202208301600'
        """
        if info != self.get_branch_name():
            LOG(LEVEL_WARN, f"The branch you set [{info}], is not same with the project you set [{self.get_branch_name()}].")
            return None
        self._gerrit_branch = info
        return self._gerrit_branch

    def GetGerritBranchInfo(self):
        """
        example: 'branch': 'tws_master_202208301600'
        """
        return self._gerrit_branch

    def _SetGerritNumber(self, number:str):
        """
        example: 'number': '256832'
        """
        if len(number) != 6:
            LOG(LEVEL_ERROR, 'Gerrit number should have 6 digits, but you set [{}]'.format(number))
        self._gerrit_number.append(number)

    def GetGerritNumber(self, index) -> str:
        """
        example: 'number': '256832'
        """
        if index >= len(self._gerrit_number):
            LOG(LEVEL_ERROR, 'The count of the Gerrit Number is [{}], but you set index [{}]'.format(
                len(self._gerrit_number), index))
        return self._gerrit_number[index]

    def _SetGerritUrl(self, url:str):
        """
        example: 'url': 'https://gerrit.huaqin.com:9443/256832'
        """
        self._gerrit_url.append(url)

    def GetGerritUrl(self, index) -> str:
        """
        example: 'url': 'https://gerrit.huaqin.com:9443/256832'
        """
        if index >= len(self._gerrit_url):
            LOG(LEVEL_ERROR, 'The count of the Gerrit URL is [{}], but you set index [{}]'.format(
                len(self._gerrit_url), index))
        self._gerrit_url[index]

    def _SetGerritPatchsetNum(self, number:str):
        """
        'currentPatchSet': {'number': '3'
        """
        self._gerrit_patchset_num.append(number)

    def GetGerritPatchSetNum(self, index:int) -> str:
        """
        'currentPatchSet': {'number': '3'
        """
        if index >= len(self._gerrit_patchset_num):
            LOG(LEVEL_ERROR, 'The count of the Patchset Number is [{}], but you set index [{}]'.format(
                len(self._gerrit_patchset_num), index))
        return self._gerrit_patchset_num[index]

    def _SetGerritRefInfo(self, ref):
        """
        'currentPatchSet': {ref': 'refs/changes/32/256832/3'
        """
        self._gerrit_ref_info.append(ref)

    def GetGerritRefInfo(self, index):
        """
        'currentPatchSet': {'ref': 'refs/changes/32/256832/3'
        """
        if index >= len(self._gerrit_ref_info):
            LOG(LEVEL_ERROR, 'The count of the Ref info is [{}], but you set index [{}]'.format(
                len(self._gerrit_ref_info), index))
        return self._gerrit_ref_info[index]

    def SetWorkingPath(self, path):
        if len(path) < len(_WORKING_ROOT_PATH):
            LOG(LEVEL_ERROR, 'Working path should under the [{}], but you set [{}]'.format(
                _WORKING_ROOT_PATH, path))
        if path[:len(_WORKING_ROOT_PATH)] != _WORKING_ROOT_PATH:
            LOG(LEVEL_ERROR, 'Working path you set do not support, please check. Path should start with [{}], but you set [{}]'.format(
                _WORKING_ROOT_PATH, path))
        self._working_dir = path

    def GetWorkingPath(self) -> str:
        if len(self._working_dir) < len(_WORKING_ROOT_PATH):
            LOG(LEVEL_ERROR, 'Working path not set yet, please set it first: [{}]'.format(self._working_dir))
        if self._working_dir[:len(_WORKING_ROOT_PATH)] != _WORKING_ROOT_PATH:
            LOG(LEVEL_ERROR, 'Working path is wrong, please check, Path should start with [{}], but now is [{}]'.format(
                _WORKING_ROOT_PATH, self._working_dir))
        return self._working_dir

    def SetCodePath(self, path):
        if len(path) <= len(self.GetWorkingPath()):
            LOG(LEVEL_ERROR, 'Code path should under the [{}], but you set [{}]'.format(
                self.GetWorkingPath(), path))
        if path[:len(self.GetWorkingPath())] != self.GetWorkingPath():
            LOG(LEVEL_ERROR, 'Code path you set do not support, please check. Path should start with [{}], but you set [{}]'.format(
                self.GetWorkingPath(), path))
        self._code_root_path = path

    def GetCodeRootPath(self) -> str:
        if len(self._code_root_path) <= len(self.GetWorkingPath()):
            LOG(LEVEL_ERROR, 'Code path not set yet, please set it first: [{}]'.format(self._code_root_path))
        if self._code_root_path[:len(self.GetWorkingPath())] != self.GetWorkingPath():
            LOG(LEVEL_ERROR, 'Code path is wrong, please check. Path should start with [{}], but now is [{}]'.format(
                self.GetWorkingPath(), self._code_root_path))
        return self._code_root_path

    def _SetGerritFileInfo(self, files):
        """
        [
            {'file': '/COMMIT_MSG', 'type': 'ADDED', 'insertions': 18, 'deletions': 0},
            {'file': 'app/ux/src/ux_box.c', 'type': 'MODIFIED', 'insertions': 8, 'deletions': 0},
            {'file': 'app/ux/src/ux_sensor_interceptor.c', 'type': 'MODIFIED', 'insertions': 1, 'deletions': -1},
            {'file': 'include/platform/frameworks/utils/kernel_property.h', 'type': 'MODIFIED', 'insertions': 3, 'deletions': 0},
            {'file': 'platform/frameworks/property/include/kv_adapter.h', 'type': 'MODIFIED', 'insertions': 3, 'deletions': 0},
            {'file': 'platform/frameworks/property/property.c', 'type': 'MODIFIED', 'insertions': 7, 'deletions': -1},
            {'file': 'platform/frameworks/property/src/bes/kv_adapter.c', 'type': 'MODIFIED', 'insertions': 14, 'deletions': 0},
            {'file': 'platform/frameworks/property/src/wq/kv_adapter.c', 'type': 'MODIFIED', 'insertions': 11, 'deletions': -1}
        ]
        """
        self._gerrit_file_list.append(files)

    def GetGerritFileInfo(self, index):
        if index >= len(self._gerrit_file_list):
            LOG(LEVEL_ERROR, 'The count of the file list Number is [{}], but you set index [{}]'.format(
                len(self._gerrit_file_list), index))
        return self._gerrit_file_list[index]

    def _SetProjectName(self, name):
        """
        ts6239
        """
        if not _PROJECT_CONFIG_INFO.get(name.upper()):
            LOG(LEVEL_ERROR, 'We can not find the project for [{}]'.format(name))
        self._project_name = name.upper()

    def GetProjectName(self):
        if not self._project_name:
            LOG(LEVEL_ERROR, 'Project Name not set yet, please set it first')
        return self._project_name

    def _CheckGerritOpenStatus(self, status):
        """
        'open': True
        """
        if status != True:
            LOG(LEVEL_ERROR, 'The gerrit status is not OPEN, please check')

    def GetCodePullCmd(self):
        cmd = _CODE_PULL_CMD_TEMPLATE % (self.account_id,
                                        _PROJECT_CONFIG_INFO.get(self._project_name).get('code_server'),
                                        _PROJECT_CONFIG_INFO.get(self._project_name).get('code_server_port'),
                                        _PROJECT_CONFIG_INFO.get(self._project_name).get('manifest')
                                        )
        return cmd

    def GetEarphoneBuildCmd(self) -> str:
        cmd = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('earphone_build_cmd')
        if not cmd:
            LOG(LEVEL_ERROR, 'Build CMD get fail, please check the _PROJECT_CONFIG_INFO')
            return ''

        return cmd

    def GetEarphoneBuildPath(self) -> str:
        if not self.GetCodeRootPath():
            LOG(LEVEL_ERROR, 'Cannot get earphone build path, please set the Code path first')
        path = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('earphone_build_dir')
        if not path:
            LOG(LEVEL_ERROR, 'Cannot get earphone build path, please check the earphone_build_dir in _PROJECT_CONFIG_INFO')
            return ''

        # test_file = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('earphone_build_test_file')
        # if not test_file:
        #   LOG(LEVEL_ERROR, 'Cannot get earphone build test file, Please check the earphone_build_test_file in _PROJECT_CONFIG_INFO')
        # test_file_path = self.GetCodeRootPath() +  test_file
        # if not os.path.isfile(test_file_path):
        #   LOG(LEVEL_ERROR, 'Cannot get earphone build test file, please check if the file exist')
        return self.GetCodeRootPath() + path

    def GetEarphoneBuildOutputPath(self) -> str:
        if not self.GetCodeRootPath():
            LOG(LEVEL_ERROR, 'Cannot get earphone build path, please set the Code path first')
        path = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('earphone_build_output_path')
        if not path:
            LOG(LEVEL_ERROR, 'Cannot get earphone build path, please check the earphone_build_output_path in _PROJECT_CONFIG_INFO')
            return ''
        return self.GetCodeRootPath() + path

    def GetEarphoneBuildTestFilePath(self) -> str:
        if not self.GetCodeRootPath():
            LOG(LEVEL_ERROR, 'Cannot get earphone build path, please set the Code path first')
        test_file = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('earphone_build_test_file')
        if not test_file:
            LOG(LEVEL_ERROR, 'Cannot get earphone build test file, Please check the earphone_build_test_file in _PROJECT_CONFIG_INFO')
        return self.GetCodeRootPath() +  test_file

    def GetEarphoneCopyFileList(self) -> list:
        work_path = self.GetCodeRootPath()
        path  = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('earphone_build_output_file_path')
        filelist = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('earphone_build_output_file_list')
        ret = []
        if (not path) or (not filelist):
            LOG(LEVEL_ERROR, 'Get earphone copy file list fail. [{}] [{}]'.format(path, filelist))
        for file in filelist:
            ret.append(work_path + path + file)

        LOG(LEVEL_INFO, filelist)
        return ret

    def GetCherrypickPathByGerryProjectName(self, name) -> str:
        if not self._manifest_project_path_dict:
            LOG(LEVEL_ERROR, "Manifest xml not parse yet.")
        for node in self._manifest_project_path_dict:
            if node.get('name') == name:
                return self.GetCodeRootPath() + node.get('path') + '/'
        LOG(LEVEL_ERROR, 'Cannot find the project [{}] in [{}] configuration'.format(
            name, self.GetProjectName()))
        return ''

    def GetCherrypickCommand(self, index) -> str:
        if not self._cherrypick_cmd_list:
            LOG(LEVEL_ERROR, 'Cherrypick command not set yet.')
        if index >= len(self._cherrypick_cmd_list):
            LOG(LEVEL_ERROR, 'Cherrypick command index error, we have [{}], but you want [{}]'.format(
                len(self._cherrypick_cmd_list), index + 1))
        return self._cherrypick_cmd_list[index]

    def GetImagePath(self, product, build_type) -> str:
        if not self._copied_image_path:
            LOG(LEVEL_ERROR, 'image path not set yet, please check')
        if (product == 'earbud') or (product == 'box'):
            if (build_type == 'org') or (build_type == 'patch'):
                return self.GetWorkingPath() + self._copied_image_path.get(product).get(build_type)
        LOG(LEVEL_ERROR, 'product [{}] or build_type [{}] error, please check'.format(product, build_type))
        return ''

    def GetCopiedImageRootPath(self, product) -> str:
        if not self._copied_image_path:
            LOG(LEVEL_ERROR, 'image path not set yet, please check')
        if (product == 'earbud') or (product == 'box'):
            return self.GetWorkingPath() + self._copied_image_path.get(product).get('root')
        LOG(LEVEL_ERROR, 'product [{}] error, please check'.format(product))
        return ''

    def GetImageFilePath(self, product, build_type, img_type) -> str:
        if self.GetEarbudPlatformType() == 'wq':
            _supported_img_type = ['map', 'bin', 'layout', 'pkg']
        elif self.GetEarbudPlatformType() == 'qcom':
            _supported_img_type = ['map', 'hex']
        else:
            _supported_img_type = ['map', 'bin']

        if not self.GetImagePath(product, build_type):
            LOG(LEVEL_ERROR, 'Get image path fail when get file path, please check')
        if img_type not in _supported_img_type:
            LOG(LEVEL_ERROR, 'Get image file path fail, please check img_type you set')
        return self.GetImagePath(product, build_type) + _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('img_file_dict').get(product).get(img_type)

    def GetJenkinsUrl(self) -> str:
        return self.jenkins_url

    def GetEarbudPlatformType(self) -> str:
        return _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('platform_type')

    def GetImpactProjectBuildInfo(self) -> list:
        impact_project_list = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get("impact_project_list")
        impact_build_info = []
        if not impact_project_list:
            return impact_project_list

        for project_name in impact_project_list:
            if project_name == self.GetProjectName():
                continue
            project_config = _PROJECT_CONFIG_INFO.get(project_name)
            build_path = self.GetCodeRootPath() + project_config.get("earphone_build_dir")
            build_cmd = project_config.get("earphone_build_cmd")
            output_path = self.GetCodeRootPath() + project_config.get("earphone_build_output_path")
            test_file = self.GetCodeRootPath() + project_config.get("earphone_build_test_file")
            output_file_path = self.GetCodeRootPath() + project_config.get("earphone_build_output_file_path")
            copy_file_list = []
            for file in project_config.get("earphone_build_output_file_list"):
                copy_file_list.append(output_file_path + file)
            impact_build_info.append((project_name, build_path, build_cmd, output_path, test_file, copy_file_list))

        return impact_build_info

    def NotifyReviewToGerrit(self, message:str, review=None):
        port = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('review_server_port')
        account = self.account_id
        server = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('review_server')
        msg = '[TWS_GUARD] ' + message
        for index in range(0, self.GetGerritProjectCount()):
            change_num = self.GetGerritNumber(index)
            patch_set = self.GetGerritPatchSetNum(index)
            cmd = _GERRIT_REVIEW_CMD_TEMPLATE % (port, account, server, "\\\'" + msg + "\\\'", change_num, patch_set)
            if review:
                cmd += review
            ret = TIMEOUT_SHELL_COMMAND(cmd, timeout=60)
            if ret[0]:
                LOG(LEVEL_WARN, 'Gerrit Review Fail, cmd= [{}]'.format(cmd))

    def ParseGerritInfo(self):
        if not self.org_gerrit_data:
            LOG(LEVEL_ERROR, "Please set 'org_gerrit_data' first")
            return
        if len(self.org_gerrit_data) <= 1:
            LOG(LEVEL_ERROR, 'No gerrit info found.')

        for line_num in range(0, len(self.org_gerrit_data) - 1):
            json_data = json.loads(self.org_gerrit_data[line_num])
            if json_data:
                if json_data.get("status") in ("ABANDONED", "MERGED"):
                    LOG(LEVEL_WARN, f"Parsing gerrit index [{line_num}] error, gerrit status error, status: [{json_data.get('status')}], branch: [{json_data.get('branch')}]")
                    continue
                if json_data.get('branch'):
                    ret = self._SetGerritBranchInfo(json_data.get('branch'))
                    if not ret:
                        LOG(LEVEL_WARN, f"Parsing gerrit index [{line_num}] error, branch name missmatch. [{json_data.get('branch')}], [{self.get_manifest_name()}]")
                        continue
                else:
                    LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('branch'))

                if json_data.get('project'):
                    self._SetGerritProjectInfo(json_data.get('project'))
                else:
                    LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('project'))

                if json_data.get('number'):
                    self._SetGerritNumber(json_data.get('number'))
                else:
                    LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('number'))

                if json_data.get('url'):
                    self._SetGerritUrl(json_data.get('url'))
                else:
                    LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('url'))

                if json_data.get('currentPatchSet'):
                    if json_data.get('currentPatchSet').get('number'):
                        self._SetGerritPatchsetNum(json_data.get('currentPatchSet').get('number'))
                    else:
                        LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('currentPatchSet.number'))

                    if json_data.get('currentPatchSet').get('ref'):
                        self._SetGerritRefInfo(json_data.get('currentPatchSet').get('ref'))
                    else:
                        LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('ref'))

                    if json_data.get('currentPatchSet').get('files'):
                        self._SetGerritFileInfo(json_data.get('currentPatchSet').get('files'))
                    else:
                        LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('currentPatchSet.files'))
                else:
                    LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('currentPatchSet'))

                if json_data.get('open'):
                    self._CheckGerritOpenStatus(json_data.get('open'))
                else:
                    LOG(LEVEL_ERROR, 'Cannot find [{}] info in gerrit'.format('open status'))

        if not self.GetGerritBranchInfo():
            LOG(LEVEL_ERROR, "Parsing gerrit info error, No valid gerrit commit found with given change ID, please check the changeId's status.")
        # self.SetWorkingPath(_WORKING_ROOT_PATH + self.change_id[-8:] + '/')
        self.SetWorkingPath(_WORKING_ROOT_PATH)
        self.SetCodePath(self.GetWorkingPath() + 'code/')

        LOG(LEVEL_INFO, 'Start parsing cherrypick command')
        cherrypick_server = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('cherrypick_server')
        cherrypick_server_port = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('cherrypick_server_port')
        for index in range(0, self.GetGerritProjectCount()):
            cmd = _CHERRYPICK_CMD_TEMPLATE % (
                                            self.account_id,
                                            cherrypick_server,
                                            cherrypick_server_port,
                                            self.GetGerritProjectInfo(index),
                                            self.GetGerritRefInfo(index))
            self._cherrypick_cmd_list.append(cmd)
        LOG(LEVEL_INFO, 'Parsing cherrypick command finished')

    def ParseProjectManifestInfo(self):
        LOG(LEVEL_INFO, 'Start parsing manifest: [{}]'.format(self.GetProjectName()))
        manifest = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('manifest')
        if not manifest:
            LOG(LEVEL_ERROR, 'Cannot fild manifest configuration in _PROJECT_CONFIG_INFO, please check')
        manifest_path = self.GetCodeRootPath() + '.repo/manifests/' + manifest
        xml_data = XMLET.parse(manifest_path)
        root = xml_data.getroot()
        for child in root:
            if child.tag == 'project':
                self._manifest_project_path_dict.append(child.attrib)
            if child.tag == 'default':
                manifest_branch_revision = child.attrib.get('revision')
                if self.get_branch_name() != manifest_branch_revision:
                    LOG(LEVEL_ERROR, 'branch_revision not match: [{}], [{}]'.format(
                        manifest_branch_revision, self.get_branch_name()))

        LOG(LEVEL_INFO, 'Parsing manifest Finished: [{}]'.format(self.GetProjectName()))

    def get_manifest_name(self):
        """_summary_

        Returns:
            _type_: _description_
        """
        manifest = _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('manifest')
        if manifest:
            return os.path.basename(manifest)
        else:
            return None

    def get_branch_name(self):
        return _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('branch_revision')

    def GetEarphoneFlashimagePath(self) -> str:
        code_root_path = self.GetCodeRootPath()
        LOG(LEVEL_INFO,f"GetEarphoneFlashimagePath:code root path: {code_root_path}")
        if not self.GetCodeRootPath():
           LOG(LEVEL_ERROR, 'Cannot get earphone flash image script path, please set the Code path first')
        path = 'qcc_xpan_sdk_20240424/tools/python_workspace/workspace_env37/bin/'
        return self.GetCodeRootPath() + path

    def GetEarbudImageFileName(self, file_type) -> str:
        return _PROJECT_CONFIG_INFO.get(self.GetProjectName()).get('img_file_dict').get('earbud').get(file_type)

    def GetImageZipRootPath(self, product) -> str:
        if (product == 'earbud') or (product == 'box'):
            return _WORKING_ROOT_PATH + self._copied_image_path.get(product).get('root')
        LOG(LEVEL_WARN, 'product [{}] error, please check'.format(product))
        return ''

    def _GetRAMFileNameWithPath(self, build_type, filename) ->str:
        img_root_path = self.GetImageZipRootPath('earbud')
        LOG(LEVEL_INFO,f"_GetRAMFilePath:code root path: {img_root_path}")
        if not img_root_path:
            LOG(LEVEL_INFO, 'Cannot get earphone code root path, please set the Code path first')
        return img_root_path + '/' +  build_type + '/' + filename

_guardInfo = _GuardInfo()


def _QueryGerritInfo():
    query_command = "ssh -p 29418 %s@gerrit.huaqin.com gerrit query %s --current-patch-set --format JSON --files" % (
        _guardInfo.account_id, _guardInfo.change_id)

    ret = TIMEOUT_SHELL_COMMAND(query_command, capture_output=True, timeout=30)
    if ret[0]:
        LOG(LEVEL_ERROR, 'Query gerrit info fail, please check the return code: [{}]'.format(ret[0]))
    # for line in gerrit_lines:
    #   LOG(LEVEL_INFO, json.loads(line))
    _guardInfo.org_gerrit_data = ret[1]
    _guardInfo.ParseGerritInfo()


def _InitReviewerWorkingEnv():
    LOG(LEVEL_INFO, 'Init the working path: [{}]'.format(_guardInfo.GetCodeRootPath()))

    if os.path.exists(_guardInfo.GetWorkingPath()):
        LOG(LEVEL_INFO, 'Removing the already existing dir: [{}]'.format(_guardInfo.GetWorkingPath()))
        ret = TIMEOUT_SHELL_COMMAND('rm -rf %s' % (_guardInfo.GetWorkingPath()), timeout=90)
        if ret[0]:
            LOG(LEVEL_ERROR, 'Fail to delete the exist working path: [{}]'.format(_guardInfo.GetWorkingPath()))

    os.makedirs(_guardInfo.GetWorkingPath())
    if (not os.path.exists(_guardInfo.GetWorkingPath())) or (not os.access(_guardInfo.GetWorkingPath(), mode=os.W_OK)):
        LOG(LEVEL_ERROR, 'Dir cannot be create or no access to it [{}]'.format(_guardInfo.GetWorkingPath()))

    os.mkdir(_guardInfo.GetCodeRootPath())
    if (not os.path.exists(_guardInfo.GetCodeRootPath())) or (not os.access(_guardInfo.GetCodeRootPath(), mode=os.W_OK)):
        LOG(LEVEL_ERROR, 'Dir cannot be create or no access to it [{}]'.format(_guardInfo.GetCodeRootPath()))

    LOG(LEVEL_INFO, 'Init the working environment successful: [{}]'.format(_guardInfo.GetWorkingPath()))


def _PullProjectCode():
    LOG(LEVEL_INFO, 'Starting to pull the code to dir [{}]'.format(_guardInfo.GetWorkingPath()))
    pull_command = _guardInfo.GetCodePullCmd()

    ret = TIMEOUT_SHELL_COMMAND(command=pull_command, timeout=900, cwd=_guardInfo.GetCodeRootPath())
    if ret[0]:
        LOG(LEVEL_ERROR, 'Pull code fail, please check. cmd:[{}]'.format(pull_command))
    #小米音响的特殊配置 start
    if _guardInfo.GetProjectName() in ("SS6950A", "SS6950B", "SS6950A_MR", "SS6950B_MR", "SS6950A_MR_TAG", "SS6950B_MR_TAG", "SS6950B_MR_0307", "SS6950A_MR_0307"):
        test_dir = _guardInfo.GetCodeRootPath() + 'rainbow_jbl_baseline/jbl/'
        if (not os.path.exists(test_dir)) or (not os.access(test_dir, mode=os.W_OK)):
            LOG(LEVEL_ERROR, 'Dir cannot be create or no access to it [{}]'.format(test_dir))
    else:
        test_dir = _guardInfo.GetCodeRootPath() + 'earphone/'
        if (not os.path.exists(test_dir)) or (not os.access(test_dir, mode=os.W_OK)):
            LOG(LEVEL_ERROR, 'Dir cannot be create or no access to it [{}]'.format(test_dir))
    #小米音响的特殊配置 end
    LOG(LEVEL_INFO, 'Pull the code successful [{}]'.format(_guardInfo.GetCodeRootPath()))


def _build_impact_project_earphone():
    build_info = _guardInfo.GetImpactProjectBuildInfo()
    gerrit_msg = ""
    impact_build_success = True
    if build_info:
        for project_name, build_path, build_cmd, output_path, test_file, copy_file_list in build_info:
            if not os.path.isfile(test_file):
                impact_build_success = False
                gerrit_msg += "FAIL project: [{}], info: [{}]\\\n\\\r".format(
                    project_name, "testfile [{}] not exist.".format(test_file)
                )
                break
            if os.path.exists(output_path):
                ret = TIMEOUT_SHELL_COMMAND('rm -rf %s' % (output_path), timeout=90)
                if ret[0]:
                    impact_build_success = False
                    gerrit_msg += "FAIL project: [{}], info: [{}]\\\n\\\r".format(
                        project_name, "cannot delete output path [{}].".format(output_path)
                    )
                    break
            if not os.access(build_path, mode=os.O_RDWR):
                impact_build_success = False
                gerrit_msg += "FAIL project: [{}], info: [{}]\\\n\\\r".format(
                    project_name, "cannot access build path [{}].".format(build_path)
                )
                break

            ret = TIMEOUT_SHELL_COMMAND(build_cmd, timeout=900, cwd=build_path)
            if ret[0]:
                impact_build_success = False
                gerrit_msg += "FAIL project: [{}], info: [{}]\\\n\\\r".format(
                    project_name, "build project fail [{}]."
                )
                break

            # for file in copy_file_list:
            #     if not os.path.isfile(file):
            #         impact_build_success = False
            #         gerrit_msg += "FAIL project: [{}], info: [{}]\\\n\\\r".format(
            #             project_name, f"Build output file does not exist [{file}]."
            #         )
            #         break
            if not impact_build_success:
                break

            gerrit_msg += "PASS project: [{}]\\\n\\\r".format(project_name)

        if impact_build_success == True:
            _guardInfo.impact_build_success = True
            gerrit_msg = "[Build Impact project] Successful. \\\n\\\r" + gerrit_msg
        else:
            _guardInfo.impact_build_success = False
            gerrit_msg = "[Build Impact project] Failed. \\\n\\\r" + gerrit_msg
        _guardInfo.NotifyReviewToGerrit(gerrit_msg)
    else:
        _guardInfo.impact_build_success = True
        gerrit_msg = "[Build Impact project] Successful: No Porject need to check\\\n\\\r"
        _guardInfo.NotifyReviewToGerrit(gerrit_msg)


def _BuildEarphone(copy_dst_path):
    LOG(LEVEL_INFO, 'Start to build the Earphone')
    build_path = _guardInfo.GetEarphoneBuildPath()
    build_cmd = _guardInfo.GetEarphoneBuildCmd()
    output_path = _guardInfo.GetEarphoneBuildOutputPath()
    test_file = _guardInfo.GetEarphoneBuildTestFilePath()

    if not os.path.isfile(test_file):
        LOG(LEVEL_ERROR, 'Cannot find the earphone test file [{}], please check.'.format(test_file))
    if os.path.exists(output_path):
        ret = TIMEOUT_SHELL_COMMAND('rm -rf %s' % (output_path), timeout=90)
        if ret[0]:
            LOG(LEVEL_ERROR, 'Cannot delete existing output dir: [ret={}] [{}]'.format(ret, output_path))
    if not os.access(build_path, mode=os.O_RDWR):
        LOG(LEVEL_ERROR, 'Cannot access build path [{}]'.format(build_path))

    ret = TIMEOUT_SHELL_COMMAND(build_cmd, timeout=900, cwd=build_path)
    if ret[0]:
        LOG(LEVEL_ERROR, 'Earphone build command execute Fail, ret = [{}]'.format(ret[0]))
    LOG(LEVEL_INFO, 'Earphone build successful.')

    if copy_dst_path:
        LOG(LEVEL_INFO, 'Start copy output file to [{}]'.format(copy_dst_path))
        if os.path.exists(copy_dst_path):
            ret = TIMEOUT_SHELL_COMMAND('rm -rf %s' % (copy_dst_path), timeout=30)
            if ret[0]:
                LOG(LEVEL_ERROR, 'Cannot delete the existing copy destination dir: [{}]'.format(copy_dst_path))
        os.makedirs(copy_dst_path)
        if not os.path.exists(copy_dst_path):
            LOG(LEVEL_ERROR, 'Create copy destination dir fail: [{}]'.format(copy_dst_path))

        for file in _guardInfo.GetEarphoneCopyFileList():
            ret = TIMEOUT_SHELL_COMMAND('cp %s %s' % (file, copy_dst_path), timeout=10)
            if ret[0]:
                LOG(LEVEL_ERROR, 'Earphone copy file fail: from=[{}] to=[{}]'.format(file, copy_dst_path))
        LOG(LEVEL_INFO, 'Copy output files successful [{}]'.format(copy_dst_path))

        build_type = copy_dst_path.split('/')[-1]
        if copy_dst_path[-1] == '/':
            build_type = copy_dst_path.split('/')[-2]
        LOG(LEVEL_INFO, 'copy_dst_path = [{}], build_type = [{}]'.format(copy_dst_path, build_type))
        if build_type == 'patch':
            LOG(LEVEL_INFO, 'Zip the {} image files Start'.format(build_type))
            zip_name = '%s_image.zip' % (build_type)
            cmd = 'zip -r %s  %s' % (zip_name, copy_dst_path)
            exe_cwd = _guardInfo.GetCopiedImageRootPath('earbud')
            ret = TIMEOUT_SHELL_COMMAND(cmd, timeout=90, cwd=exe_cwd)
            if ret[0]:
                LOG(LEVEL_INFO, 'Zip the {} image files fail'.format(build_type))
            else:
                LOG(LEVEL_INFO, 'Zip the {} image files successful'.format(build_type))
                gerrit_msg = '[Patch Build] SUCCESSFUL  \\\n\\\r'
                # http://192.168.29.22:8080/job/tws_guard_2/24/artifact/working/cppcheck_report.zip
                # result_url = "%sartifact/%s%s" % (_guardInfo.jenkins_url, _WORKING_ROOT_DIR, zip_name)
                # gerrit_msg += 'You can download the patch build image in {}'.format(result_url)
                _guardInfo.NotifyReviewToGerrit(gerrit_msg)


def _CherrypickThePatch():
    'git fetch ssh://101002563@gerrit.huaqin.com:29418/HQ_BD1SW_PA1952/earphone refs/changes/78/256878/1 && git cherry-pick FETCH_HEAD'
    for index in range( _guardInfo.GetGerritProjectCount()):
        cherrypick_cmd = _guardInfo.GetCherrypickCommand(index)
        cherrypick_path = _guardInfo.GetCherrypickPathByGerryProjectName(_guardInfo.GetGerritProjectInfo(index))
        ret = TIMEOUT_SHELL_COMMAND(cherrypick_cmd, timeout=300, cwd=cherrypick_path)
        if ret[0]:
            gerrit_msg = '[Patch Build] Cherry-pick Fail'
            _guardInfo.NotifyReviewToGerrit(gerrit_msg)
            LOG(LEVEL_ERROR, 'Cherry-pick fail: [{}] [{}]'.format(cherrypick_cmd, cherrypick_path))


def _DoBinSizeCheck():
    org_bin_path = _guardInfo.GetImageFilePath('earbud', 'org', 'bin')
    patch_bin_path = _guardInfo.GetImageFilePath('earbud', 'patch', 'bin')
    org_bin_size = os.path.getsize(org_bin_path)
    patch_bin_size = os.path.getsize(patch_bin_path)
    diff_size = patch_bin_size - org_bin_size

    LOG(LEVEL_INFO, 'patch_bin_size: [{}] - org_bin_size [{}] = [{}] Bytes.'.format(
            patch_bin_size, org_bin_size, diff_size))
    review_info = '[BIN Size Check]\\\n\\\r'
    review_info = review_info + 'patch_bin_size: [{}] - org_bin_size [{}] = [{}] Bytes.'.format(
            patch_bin_size, org_bin_size, diff_size)
    _guardInfo.NotifyReviewToGerrit(review_info)
    pass


def _DoBesFreeRamCheck():
    _VALID_FREERAM_LIST = ['__free_ram', '__free_ramcp', '__free_ramcpx', '__free_fram']
    if _guardInfo.GetProjectName() in ("PA8414", "TS7037A","SS6950A", "SS6950B", "SS6950A_MR", "SS6950B_MR", "SS6950A_MR_TAG", "SS6950B_MR_TAG", "SS6950B_MR_0307", "SS6950A_MR_0307"):
        _VALID_FREERAM_LIST = ['__free_ram', '__free_fram']
    def _FindFreeRamLines(path) -> dict:
        _ALL_FREERAM_PATTERN = re.compile(r'__free_ram|__free_fram')
        ret_dict = {}
        fd = open(path, mode='r', encoding='utf8')
        lines = fd.readlines()
        fd.close()
        for line in lines:
            if _ALL_FREERAM_PATTERN.search(line):
                line = line.strip()
                info = re.split(r' +', line, 2)
                if info[1] not in _VALID_FREERAM_LIST:
                    continue
                if info[0][:2] != '0x':
                    continue
                ret_dict.setdefault(info[1], info[0])
        if _guardInfo.GetProjectName() in ("PA8414", "TS7037A","SS6950A", "SS6950B", "SS6950A_MR", "SS6950B_MR", "SS6950A_MR_TAG", "SS6950B_MR_TAG", "SS6950B_MR_0307", "SS6950A_MR_0307"):
            if len(ret_dict) != 2:
                LOG(LEVEL_ERROR, 'BES free ram check fail, the lines we found are [{}]'.format(ret_dict))
        else:
            if len(ret_dict) != 4:
                LOG(LEVEL_ERROR, 'BES free ram check fail, the lines we found are [{}]'.format(ret_dict))
        return ret_dict

    org_map_path = _guardInfo.GetImageFilePath('earbud', 'org', 'map')
    patch_map_path = _guardInfo.GetImageFilePath('earbud', 'patch', 'map')
    org_ram_dict = _FindFreeRamLines(org_map_path)
    patch_ram_dict = _FindFreeRamLines(patch_map_path)
    LOG(LEVEL_INFO, 'ORG  : [{}]'.format(org_ram_dict))
    LOG(LEVEL_INFO, 'PATCH: [{}]'.format(patch_ram_dict))

    review_info = '[BES free_ram check]\\\n\\\r'
    for item in _VALID_FREERAM_LIST:
        org_hex_str = org_ram_dict.get(item)
        org_dec = int(org_hex_str, base=16)
        patch_hex_str = patch_ram_dict.get(item)
        patch_dec = int(patch_hex_str, base=16)
        diff_dec = patch_dec - org_dec
        LOG(LEVEL_INFO, '[{:<13}]: PATCH[{}][{:^7}] - ORG[{}][{:^7}] = [{}]'.format(
                item, patch_hex_str, patch_dec, org_hex_str, org_dec, diff_dec))
        review_info = review_info + '[{:<13}]: PATCH[{}][{:^7}] - ORG[{}][{:^7}] = [{}]\\\n\\\r'.format(
                item, patch_hex_str, patch_dec, org_hex_str, org_dec, diff_dec)

    _guardInfo.NotifyReviewToGerrit(review_info)


def _DoWuqiMemoryConfigCheck():
    org_memcfg_path = _guardInfo.GetImageFilePath('earbud', 'org', 'layout')
    patch_memcfg_path = _guardInfo.GetImageFilePath('earbud', 'patch', 'layout')
    fd = open(org_memcfg_path, 'r', encoding='utf8')
    org_fdata = fd.read()
    fd.close()

    fd = open(patch_memcfg_path, 'r', encoding='utf8')
    patch_fdata = fd.read()
    fd.close()

    review_info = '[WuQi memory config check]\\\n\\\r'

    org_json_data = json.loads(org_fdata)
    org_images_list = org_json_data.get("images")

    patch_json_data = json.loads(patch_fdata)
    patch_images_list = patch_json_data.get("images")
    for patch_image in patch_images_list:
        patch_image_name = patch_image.get('name')
        patch_image_length = patch_image.get('length')
        for org_image in org_images_list:
            org_image_name = org_image.get('name')
            org_image_length = org_image.get('length')
            if patch_image_name == org_image_name:
                # LOG(LEVEL_INFO, '[{:<13}]: PATCH[{}][{:^7}] - ORG[{}][{:^7}] = [{}]'.format(
                #         item, patch_hex_str, patch_dec, org_hex_str, org_dec, diff_dec))
                # review_info = review_info + '[{:<13}]: PATCH[{}][{:^7}] - ORG[{}][{:^7}] = [{}]\\\n\\\r'.format(
                #         item, patch_hex_str, patch_dec, org_hex_str, org_dec, diff_dec)
                break

    _guardInfo.NotifyReviewToGerrit(review_info)


def _DoWuqiBinSizeCheck():
    org_pkg_path = _guardInfo.GetImageFilePath("earbud", "org", "pkg")
    patch_pkg_path = _guardInfo.GetImageFilePath("earbud", "patch", "pkg")
    image_list = ("dsp_tws_app.bin", "fw_updater_core0.bin", "pbl_core0.bin",
                  "sbl_core0.bin", "tone.bin", "tws_core0.bin",
                  "tws_core1.bin")
    org_image_info_dict = {}
    patch_image_info_dict = {}
    with zipfile.ZipFile(org_pkg_path, "r") as pkg:
        for file_name in image_list:
            org_image_info_dict[file_name] = pkg.getinfo(file_name).file_size

    with zipfile.ZipFile(patch_pkg_path, "r") as pkg:
        for file_name in image_list:
            patch_image_info_dict[file_name] = pkg.getinfo(file_name).file_size

    review_info = '[Wuqi Bin size check]\\\n\\\r'
    patch_total_size = 0
    org_total_size = 0
    diff_total_size = 0
    for file_name in image_list:
        patch_bin_size = patch_image_info_dict.get(file_name)
        patch_total_size += patch_bin_size
        org_bin_size = org_image_info_dict.get(file_name)
        org_total_size += org_bin_size
        diff_size = patch_bin_size - org_bin_size
        diff_total_size += diff_size
        review_info = review_info + '[{:<20}]: patch: [{:<8}] - org [{:<8}] = [{:<5}] Bytes.\\\n\\\r'.format(
                file_name, patch_bin_size, org_bin_size, diff_size)

    review_info = review_info + '[{:<20}]: patch: [{:<8}] - org [{:<8}] = [{:<5}] Bytes.\\\n\\\r'.format(
            "TOTAL", patch_total_size, org_total_size, diff_total_size)
    _guardInfo.NotifyReviewToGerrit(review_info)


def _DoWuqiFreeRamCheck():
    org_map_path = _guardInfo.GetImageFilePath('earbud', 'org', 'map')
    patch_map_path = _guardInfo.GetImageFilePath('earbud', 'patch', 'map')
    org_map_parser = map_analyzer.MapParser(org_map_path, "org", log_printer=LOG)
    org_map_parser.StartParse()
    patch_map_parser = map_analyzer.MapParser(patch_map_path, "org", log_printer=LOG)
    patch_map_parser.StartParse()
    org_ram_sections = {}
    patch_ram_sections = {}
    for org_section in org_map_parser.sections_list:
        if org_section.get(map_analyzer.SECTIONS_DICT_KEYS[2]) == "ram":
            # org_ram_sections['.iram_text'] = 0xa35c
            org_ram_sections[org_section.get(map_analyzer.SECTIONS_DICT_KEYS[3])] = org_section.get(map_analyzer.SECTIONS_DICT_KEYS[6])
    for patch_section in patch_map_parser.sections_list:
        if patch_section.get(map_analyzer.SECTIONS_DICT_KEYS[2]) == "ram":
            # org_ram_sections['.iram_text'] = 0xa35c
            patch_ram_sections[patch_section.get(map_analyzer.SECTIONS_DICT_KEYS[3])] = patch_section.get(map_analyzer.SECTIONS_DICT_KEYS[6])

    review_info = '[WuQi ram size check]\\\n\\\r'
    org_ram_size_total = 0
    patch_ram_size_total = 0
    for section_name in org_ram_sections:
        org_ram_size_hex = org_ram_sections.get(section_name)
        org_ram_size_dec = int(org_ram_size_hex, base=16)
        org_ram_size_total += org_ram_size_dec
        patch_ram_size_hex = patch_ram_sections.get(section_name, '0x0')
        patch_ram_size_dec = int(patch_ram_size_hex, base=16)
        patch_ram_size_total += patch_ram_size_dec
        diff_dec = patch_ram_size_dec - org_ram_size_dec
        LOG(LEVEL_INFO, '[{:<13}]: PATCH[{}][{:^7}] - ORG[{}][{:^7}] = [{}]'.format(
                section_name, patch_ram_size_hex, patch_ram_size_dec, org_ram_size_hex, org_ram_size_dec, diff_dec))
        review_info = review_info + '[{:<13}]: PATCH[{}][{:^7}] - ORG[{}][{:^7}] = [{}]\\\n\\\r'.format(
                section_name, patch_ram_size_hex, patch_ram_size_dec, org_ram_size_hex, org_ram_size_dec, diff_dec)

    section_name = "Total"
    LOG(LEVEL_INFO, '[{:<13}]: PATCH[{}][{:^7}] - ORG[{}][{:^7}] = [{}]'.format(
            section_name, hex(patch_ram_size_total), patch_ram_size_total, hex(org_ram_size_total), org_ram_size_total, patch_ram_size_total - org_ram_size_total))
    review_info = review_info + '[{:<13}]: PATCH[{}][{:^7}] - ORG[{}][{:^7}] = [{}]\\\n\\\r'.format(
            section_name, hex(patch_ram_size_total), patch_ram_size_total, hex(org_ram_size_total), org_ram_size_total, patch_ram_size_total - org_ram_size_total)
    _guardInfo.NotifyReviewToGerrit(review_info)

#Add Qcom parition and FreeRam size check.
_INFO_IMG_START = 'Name'
_INFO_IMG_END   = '----- static -----'
_INFO_TOTAL_INTVAL = 'TOTAL (Int) '
def _get_img_info_start_end_line_pos(lines):
    start_line = 0
    end_line   = 0
    for i, line in enumerate(lines):
        if line.startswith(_INFO_IMG_START):
            LOG(LEVEL_INFO,'img_info_start_line_pos: %s' % (i+1))
            start_line = i + 2
        elif line.startswith(_INFO_IMG_END) : #_INFO_IMG_END in line:
            LOG(LEVEL_INFO,'img_info_end_line_pos: %s' % (i-1))
            end_line = i -1
            break
    return start_line, end_line

def _get_total_info_line_pos(lines):
    for i, line in enumerate(lines):
        if _INFO_TOTAL_INTVAL in line:
            LOG(LEVEL_INFO,'total_info_line_pos: %s' % i)
            return i

def _convert_lines_data(ori_lines)->list:
    dest_lines = []
    for line in ori_lines:
        line = line.split('|')
        # line[0] = line[0].replace(' ', '-') # name 空格换成字符'-',因多个空格在gerrit网页comment只会显示1个;
        line = [item.strip() for item in line]
        dest_lines.append(line)
    return dest_lines

def _get_occupied_symbol_num_for_display(symbol_num_dict, symbol_str):
    num = 0
    for k,v in symbol_num_dict.items():
        if k in symbol_str:
            num = v
            break
    return num

def _pack_custom_format_str_data(ori_str, insert_special_symbol, insert_num):
    dst_str = ori_str
    for _ in range(insert_num):
        dst_str += insert_special_symbol
    return dst_str

def _convert_lines_data_for_htmldisplay(ori_lines)->list: # 转换成供html显示的差异化字符数量的 name
    dest_lines = []
    for line in ori_lines:
        line = line.split('|')
        occupied_symbol_num = _get_occupied_symbol_num_for_display(_occupied_symbol_num_dict, line[0])
        line = [item.strip() for item in line]
        line[0] = _pack_custom_format_str_data(line[0], '-', occupied_symbol_num) # name后面添加差异化的'-'
        dest_lines.append(line)
    return dest_lines

_occupied_symbol_num_dict = {'tme_patch': 12, 'sbl_loader':12, 'sbl':20, 'tme_qti_misc':9, 'tme_oem_misc':7, 'oem_secure':10, 
                             'cnss_cam_patch':6, 'audio_framework':4, 'ro_cfg_fs':13, 'ro_fs':18}
_show_name_order_list = ['oem_secure', 'ro_fs']

def _custom_sort_dict(ori_dict, nameorder_list)->dict:
    dst_dict = dict()
    for name in nameorder_list:
         for k,v in ori_dict.items():
            if name in k:
                dst_dict[k] = v

    for key,val in ori_dict.items():
        if key not in nameorder_list:
            dst_dict[key] = val
    print(f'_custom_sort_dict:dst_dict:{dst_dict}')
    return dst_dict

# 解析earbud.hex文件的工具位置：./qcc_xpan_sdk_20240424/tools/python_workspace/workspace_env37/bin/flash_image
# 命令：./qcc_xpan_sdk_20240424/tools/python_workspace/workspace_env37/bin/flash_image -o earbud/workspace/QCC7226-AA_DEV-BRD-AA_SENSOR/output/earbud.hex -p -f 128
'''
-----------------------+-------+----------+----------+----------+--------+------------------+--------+-----------+------------+--------------
Name                   | Index | Offset   | Capacity | Size     | % used | Content          | Signed | Encrypted | Compressed | Flags
=======================+=======+==========+==========+==========+========+==================+========+===========+============+==============
tme_patch              | 0x0   | 0x7000   | 0x7000   | 0x6914   | 93.8   | TMEL_RAM_PATCH   | yes    | no        | no         | upgradable
sbl_loader             | 0x0   | 0xe000   | 0x8000   | 0x7e40   | 98.6   | SBL_L            | no     | no        | no         | upgradable
sbl                    | 0x0   | 0x16000  | 0xd000   | 0xccf0   | 98.5   | XBL_SC           | no     | yes       | no         | upgradable
.......
----- static -----
factory_default_config | 0x0   | 0xfa8000 | 0x1000   | 0x5c0    | 35.9   | ro_fs            | -      | -         | -          | static
ra_partition           | 0x0   | 0xfa9000 | 0x1000   | Unknown  |  -     | None             | -      | -         | -          | rw,static
.......
TOTAL (Int)            |  -    |  -       | 8364032  | 5465086  |  -     |  -               |  -     |  -        |            |
-----------------------+-------+----------+----------+----------+--------+------------------+--------+-----------+------------+--------------
'''
_CURRENT_PATH = os.getcwd() +'/'
_SCRIPT_TOOL_FILE = 'flash_image'

def _get_hex_partition_info(script_path, filename=''):
    info_dict_list = [] # [info_dict, total_dict]
    script_tool = script_path + _SCRIPT_TOOL_FILE
    LOG(LEVEL_INFO,f'get hex partition info: script_tool: ${script_tool}')

    if not os.path.isfile(script_tool):
        LOG(LEVEL_INFO,'no scripte tool,please check it!!!')
        return info_dict_list
    if not os.path.isfile(filename):
        LOG(LEVEL_INFO,'no file to parser,please check it!!!')
        return info_dict_list
    cmd = f'{script_tool} -o {filename} -p -f 128'
    ret = TIMEOUT_SHELL_COMMAND(cmd,timeout=70,capture_output=True)

    image_info_dict  = {} # {name: [Size, %used]}
    total_info_dict  = {} # {name: [Capacity ,Size]}

    if not ret[0] and ret[1]:
        LOG(LEVEL_INFO,'script excute successful result:\n')
        img_start_end_line_pos  = _get_img_info_start_end_line_pos(ret[1])

        lines = _convert_lines_data(ret[1]) # 每行转换每个字段转换成list元素[ [Name,Index,...,Size,...], [], ...]
        img_start_line_pos      = img_start_end_line_pos[0]
        img_end_line_pos        = img_start_end_line_pos[1]
        img_info_lines          = lines[img_start_line_pos:img_end_line_pos+1] # [ [name,index,...,size,...], [],...]

        # 显示名称格式转换为name+idx后面跟差异化数量的补齐字符'-',比如：oem_secure[0]----------[-42440]= ORG[ 2373340 ] - PATCH[ 2330900 ]
        for line in img_info_lines:
            if len(line) < 6:
                LOG(LEVEL_INFO,'this line list data number < 6.\n')
                continue
            occupied_symbol_num = _get_occupied_symbol_num_for_display(_occupied_symbol_num_dict, line[0])
            line[0] = line[0] + '[' + str(int(line[1], base=16)) + ']'
            line[0] = _pack_custom_format_str_data(line[0], '-', occupied_symbol_num)


        for line in img_info_lines:
            if len(line) < 6:
                LOG(LEVEL_INFO,'this line list data number < 6.\n')
                continue
            name_and_idx = line[0]
            LOG(LEVEL_INFO,'key str: %s, ori size str:%s' % (name_and_idx, line[4]))
            try:
                size = int(line[4], base=16)
            except ValueError as e:
                LOG(LEVEL_INFO,'size str convert int fail info: %s' % e)
                continue
            used_percent = float(line[5])

            if name_and_idx in image_info_dict:
                tmp_size = image_info_dict[name_and_idx][1] + size
                LOG(LEVEL_INFO,'already exist name_and_idx item, tmp_size=%s' % tmp_size)
                image_info_dict[name_and_idx] = [tmp_size, used_percent] # todo
                continue

            image_info_dict[name_and_idx] = [size, used_percent] # {name: size, %used}

        total_info_line_pos     = _get_total_info_line_pos(ret[1])
        total_info_line         = lines[total_info_line_pos] # 每行的各元素存在一个列表中
        total_info_dict_key     = total_info_line[0][0:5] # 取total字符
        total_capacity          = int(total_info_line[3]) # int(total_info_line[3], base=16)
        total_size              = int(total_info_line[4]) # int(total_info_line[4], base=16)
        LOG(LEVEL_INFO, f'total info, total capacity={total_capacity}, total size={total_size}')
        total_info_dict[total_info_dict_key] = [total_capacity, total_size]

        image_info_dict = _custom_sort_dict(image_info_dict, _show_name_order_list) # 转换成自定义的显示顺序
        info_dict_list = [image_info_dict, total_info_dict]
    else:
        LOG(LEVEL_INFO,'script excute Failure, return empty list:info_dict_list!!!\n')
    return info_dict_list

def _show_diff_partinfo(patch_dict, ori_dict):
    diff_msg = ''
    if len(ori_dict) == 0 or len(patch_dict) == 0:
        LOG(LEVEL_INFO,'_show_diff_partinfo: ori_dict or patch_dict is empty!!!\n')
        return diff_msg
    for k, v in patch_dict.items(): # {section info:[size, used %], section info2: [size, used %], ......}
        ori_size    = ori_dict[k][0]  # used size
        patch_size  = v[0]
        diff_size   = patch_size - ori_size

        ori_used    = ori_dict[k][1] # used percent
        patch_used  = v[1]
        # diff_msg    = diff_msg + f'{k:27}: PATCH [{patch_size:<8}]  -  ORG [{ori_size:<8}] = [{diff_size:<7}], PATCH used: [{patch_used:<5}],  ORG used: [{ori_used:<5}]\\\n\\\r'
        diff_msg = diff_msg + '{} : [{:^10}] = PATCH [{:^10}] - ORG [{:<10}], PATCH used: [{:^6}%],  ORG used: [{:^6}%]\\\n\\\r'.format(
                                k, diff_size, patch_size, ori_size, patch_used, ori_used)
    # LOG(LEVEL_INFO, diff_msg)
    return diff_msg

def _show_diff_totalinfo(patch_dict, ori_dict):
    diff_msg = ''
    if len(ori_dict) == 0 or len(patch_dict) == 0:
        LOG(LEVEL_INFO,'_show_diff_totalinfo: ori_dict or patch_dict is empty!!!\n')
        return diff_msg
    for k, v in patch_dict.items(): # total info: [capacity, size]
        ori_capsize = ori_dict[k][0]
        patch_capsize = v[0]
        diff_capsize = patch_capsize - ori_capsize

        ori_usedsize    = ori_dict[k][1]
        patch_usedsize  = v[1]
        diff_usedsize    = patch_usedsize - ori_usedsize

        diff_msg = diff_msg + f"{k} :\\\n\\\r Total Capacity size : [ {diff_capsize} ] = PATCH[ {patch_capsize} ] - ORG[ {ori_capsize} ], \\\n\\\r Total UsedInfo size:[ {diff_usedsize} ] = PATCH [ {patch_usedsize} ] - ORG [ {ori_usedsize} ]"
    LOG(LEVEL_INFO, diff_msg)
    return diff_msg

def _DoQcomHexSizeCheck():
    review_info = '[Qcom Hex size check]\\\n\\\r'
    ori_file_name = ''
    patch_file_name = ''

    current_script_path =_guardInfo.GetEarphoneFlashimagePath()
    LOG(LEVEL_INFO, f"GetEarphoneFlashimagePath script_path: {current_script_path}")
    ori_file_name = _guardInfo.GetImageFilePath('earbud', 'org', 'hex')
    if not os.path.isfile(ori_file_name):
        LOG(LEVEL_INFO, 'No match origal hex image file name to check!!!')
        review_info = review_info + 'No match origal hex image file to check, please check if project generate hex image.'
        _guardInfo.NotifyReviewToGerrit(review_info)
        return

    patch_file_name = _guardInfo.GetImageFilePath('earbud', 'patch', 'hex')
    if not os.path.isfile(patch_file_name):
        LOG(LEVEL_INFO, 'No match patch hex image file name!!!')
        review_info = review_info + 'No match patch hex image file to check, please check if project generate hex image.'
        _guardInfo.NotifyReviewToGerrit(review_info)
        return

    ori_section_dict_list = []
    ori_section_dict_list = _get_hex_partition_info(current_script_path, ori_file_name)
    if not ori_section_dict_list:
        LOG(LEVEL_INFO, 'ori_section_dict_list is none or empty!!!')
        review_info = review_info + '_get_hex_partition_info:get ori hex info fail...!!!'
        _guardInfo.NotifyReviewToGerrit(review_info)
        return

    patch_section_dict_list = []
    patch_section_dict_list = _get_hex_partition_info(current_script_path, patch_file_name)
    if not patch_section_dict_list:
        LOG(LEVEL_INFO, 'patch_section_dict_list is none or empty!!!')
        review_info = review_info + '_get_hex_partition_info:get patch hex info fail...!!!'
        _guardInfo.NotifyReviewToGerrit(review_info)
        return

    _output_diff_msg1 = _show_diff_partinfo(patch_section_dict_list[0], ori_section_dict_list[0])
    _output_diff_msg2 = _show_diff_totalinfo(patch_section_dict_list[1], ori_section_dict_list[1])
    review_info = review_info + _output_diff_msg1 + _output_diff_msg2
    # LOG(LEVEL_INFO, '==========================================================================')
    # LOG(LEVEL_INFO, f'review_info all msg: {review_info}')
    _guardInfo.NotifyReviewToGerrit(review_info)
    return

#====================QCOM RAM Check Size Function=======================================================================
'''
命令：/opt/qtil/llvm17/bin/llvm-size out/sensor/app.elf
结果：
   text    data     bss     dec     hex filename
 109460     284   67020  176764   2b27c out/sensor/app.elf
 命令：/opt/qtil/llvm17/bin/llvm-size out/earbud.elf
 结果：
    text    data     bss     dec     hex filename
3501007   20456  426700 3948163  3c3e83 out/earbud.elf
RAM显示效果:
sensor subsystem:
text : [xxx] = ORG[xxx] - PATCH[xxx]
data : [xxx] = ORG[xxx] - PATCH[xxx]
bss  : [xxx] = ORG[xxx] - PATCH[xxx]
app subsystem:
text : [xxx] = ORG[xxx] - PATCH[xxx]
data : [xxx] = ORG[xxx] - PATCH[xxx]
bss  : [xxx] = ORG[xxx] - PATCH[xxx]
'''
_QCOM_RAM_VIEW_TOOL_NAME = 'llvm-size'
def _get_qcomhex_ram_info(script_path, filename) ->dict:
    script_tool = script_path + _QCOM_RAM_VIEW_TOOL_NAME
    cmd = f'{script_tool} {filename}'
    ret = TIMEOUT_SHELL_COMMAND(cmd,timeout=70,capture_output=True)
    # ret = [0, ['   text    data     bss     dec     hex filename','3501007   20456  426700 3948163  3c3e83 out/earbud.elf'] ]
    # lines 获取命令返回的结果行信息的list
    ram_info_dict = {} # {text:size, data:size, bss:size}
    if not ret[0] and ret[1]:
        name_line = ret[1][0].split()
        val_line  = ret[1][1].split()
        for i in range(3): # 取前3项值:text, data, bss
            ram_info_dict[name_line[i]] = val_line[i]
    return ram_info_dict

def _show_diff_ram_info(patch_dict, ori_dict):
    diff_msg = ''
    for key,val in patch_dict.items(): # { app:{text:xxx, data:xxx, bss:xxx}, sensor:{} }
        patch_text_size = val.get('text')
        patch_data_size = val.get('data')
        patch_bss_size  = val.get('bss')

        org_text_size = ori_dict.get(key).get('text')
        org_data_size = ori_dict.get(key).get('data')
        org_bss_size  = ori_dict.get(key).get('bss')

        diff_text_size = int(patch_text_size) - int(org_text_size)
        diff_data_size = int(patch_data_size) - int(org_data_size)
        diff_bss_size  = int(patch_bss_size)  - int(org_bss_size)

        diff_msg += f'{key:<16}:\\\n\\\r text--: [ {diff_text_size} ] = PATCH[{patch_text_size}] - ORG[{org_text_size}] \\\n\\\r'
        diff_msg += f' data-: [ {diff_data_size} ] = PATCH[{patch_data_size}] - ORG[{org_data_size}] \\\n\\\r'
        diff_msg += f' bss--: [ {diff_bss_size} ] = PATCH[{patch_bss_size}] - ORG[{org_bss_size}] \\\n\\\r'
    return diff_msg

def _DoQcomFreeRamCheck():
    script_tool_path = '/opt/qtil/llvm17/bin/'
    ori_ram_dict = {}
    patch_ram_dict = {}
    review_info = '[Qcom RAM Size Check]\\\n\\\r'
    ori_app_ram_file    = _guardInfo._GetRAMFileNameWithPath('org', 'earbud.elf')
    ori_sensor_ram_file = _guardInfo._GetRAMFileNameWithPath('org', 'app.elf')
    LOG(LEVEL_INFO, f"ori_app_ram_file:{ori_app_ram_file}, ori_sensor_ram_file:{ori_sensor_ram_file}")

    ori_app_ram_dict = _get_qcomhex_ram_info(script_tool_path, ori_app_ram_file)
    # for k,v in ori_app_ram_dict.items():
    #     LOG(LEVEL_INFO, f'ori key:{k}, value:{v}')
    ori_sensor_ram_dict = _get_qcomhex_ram_info(script_tool_path, ori_sensor_ram_file)
    # for k,v in ori_sensor_ram_dict.items():
    #     LOG(LEVEL_INFO, f'ori key:{k}, value:{v}')

    ori_ram_dict['app subsytem']    = ori_app_ram_dict
    ori_ram_dict['sensor subsytem'] = ori_sensor_ram_dict

    patch_app_ram_file    = _guardInfo._GetRAMFileNameWithPath('patch', 'earbud.elf')
    patch_sensor_ram_file = _guardInfo._GetRAMFileNameWithPath('patch', 'app.elf')
    LOG(LEVEL_INFO, f"patch_app_ram_file:{patch_app_ram_file}, patch_sensor_ram_file:{patch_sensor_ram_file}")

    patch_app_ram_dict = _get_qcomhex_ram_info(script_tool_path, patch_app_ram_file)
    # for k,v in patch_app_ram_dict.items():
    #     LOG(LEVEL_INFO, f'patch key:{k}, value:{v}')
    patch_sensor_ram_dict = _get_qcomhex_ram_info(script_tool_path, patch_sensor_ram_file)
    # for k,v in patch_sensor_ram_dict.items():
    #     LOG(LEVEL_INFO, f'patch key:{k}, value:{v}')

    patch_ram_dict['app subsytem']    = patch_app_ram_dict
    patch_ram_dict['sensor subsytem'] = patch_sensor_ram_dict

    review_info += _show_diff_ram_info(patch_ram_dict, ori_ram_dict)
    LOG(LEVEL_INFO, f'Qcom RAM info:=================================\\\n\\\r{review_info}')
    _guardInfo.NotifyReviewToGerrit(review_info)
#end Qcom partition and FreeRam size check

def _DoResourceCheck():
    if _guardInfo.GetEarbudPlatformType() == 'bes':
        _DoBinSizeCheck()
        if _guardInfo.GetProjectName() not in ("SHARP"):
            _DoBesFreeRamCheck()
        # _DoBesResourceDetailCheck()
    elif _guardInfo.GetEarbudPlatformType() == 'wq':
        _DoWuqiBinSizeCheck()
        _DoWuqiFreeRamCheck()
    elif _guardInfo.GetEarbudPlatformType() == 'qcom':
        try:
            if not _guardInfo.GetEarbudImageFileName('hex'):
                LOG(LEVEL_INFO, f"no-hex qcom image file, not support resource check!!!")
                return
            _DoQcomHexSizeCheck()
            _DoQcomFreeRamCheck()
        except Exception as e:
            LOG(LEVEL_WARN, f"Qcom DoResourceCheck exception:{e}")

LINT_ERROR_SHOW_KWORDS = '[lint_errshow]:'
_LINT_CONFIG_INI = 'lint_config.ini'
def _DoTwsLintCheck():
    # lint_script = _guardInfo.GetWorkingPath() + 'tws_lint_v0.2.py'
    work_path = _guardInfo.GetWorkingPath()
    lint_version = _PROJECT_CONFIG_INFO.get(_guardInfo.GetProjectName()).get('twslint_version')
    if (lint_version is None) or (lint_version == 'v0.2'): # 若twslint_version 为None或v0.2，则按v0.2旧的filter方式做lint例外检查
        LOG(LEVEL_INFO,f"[use old filter check for exclusion: {_guardInfo.GetProjectName()}].")
        _TWS_LINT_FILTER_FILE_LIST = ("tgt_hardware.h", "res_audio_data.h", "res_audio_data_cn.h")
        if (_guardInfo.GetProjectName() == "TS6938A"):
            _TWS_LINT_FILTER_FILE_LIST = ("tgt_hardware.h", "res_audio_data.h", "res_audio_data_cn.h","kernel_log.h","platform_log.h","miwear_mfps.h","miwear_mfps.c")

        lint_script = _TOOLS_PATH + 'tws_lint_v0.2.py'
        lint_configs = "_null_config_,"
    else:
        lint_script = _TOOLS_PATH + 'tws_lint_v0.3.py'   # twslint_version字段为0.3，则按lintv0.3新方式做lint例外检查
        lint_configs = work_path + _LINT_CONFIG_INI  # 赋值配置文件名
        configitems = ''

    _TWS_LINT_FILTER_PATH_LIST = ["product/earphone/[0-9a-zA-Z_]+/chip","app/rainbow/mma","device/sensor/imu_sensor/icm42607/driver","device/sensor/cap_sensor/gh6212","device/sensor/imu_sensor/icm42607/adapter","platform/external/include","platform/external/src"]

    if _PROJECT_CONFIG_INFO.get(_guardInfo.GetProjectName()).get('check_safe_function'):
        if (lint_version is None) or (lint_version == 'v0.2'): # 若twslint_version 为None或v0.2，则按v0.2.py解析
            lint_configs += "need_check_safe_func,"
        else:  # twslint version: v0.3,根据项目信息_PROJECT_CONFIG_INFO的check_safe_function字段，生成临时配置ini文件,供lintv0.3.py解析用
            configitems += "CHECK_SECURE_FUNC,"
            LOG(LEVEL_INFO, f"lint_configs file:{lint_configs}, lint_configs: {configitems}")
            config = configparser.ConfigParser()
            config.add_section('root')
            config.set('root', 'special_checklint_item', configitems)
            try:
                with open(lint_configs, 'w', encoding='utf-8') as fd:
                    config.write(fd)
            except Exception as e:
                LOG(LEVEL_WARN, 'Cannot open special lint config file [{}], please check, [{}]'.format(lint_configs, e))


    files = ''
    code_root_path = _guardInfo.GetCodeRootPath()
    code_root_path_length = len(code_root_path)
    tws_lint_result_filename = 'tws_lint_check_result.log'
    for index in range(0, _guardInfo.GetGerritProjectCount()):
        gerrit_project_name = _guardInfo.GetGerritProjectInfo(index)
        if gerrit_project_name in _PROJECT_CONFIG_INFO.get(_guardInfo.GetProjectName()).get('twslint_project'):
            code_path = _guardInfo.GetCherrypickPathByGerryProjectName(gerrit_project_name)
            for file in _guardInfo.GetGerritFileInfo(index):
                if file.get('file') == '/COMMIT_MSG':
                    continue
                if file.get("type") == "DELETED":
                    continue
                if file.get('file')[file.get('file').rfind('.') + 1:] not in ['h', 'c']:
                    continue

                if (lint_version is None) or (lint_version == 'v0.2'): # 若lint version 为None或v0.2版本，则做按v0.2的filter方式做lint例外检查
                    LOG(LEVEL_INFO,f"[use old filter check for exclusion: {_guardInfo.GetProjectName()}].")
                    if os.path.basename(file.get('file')) in _TWS_LINT_FILTER_FILE_LIST:
                        continue

                _file_path_in_filter = False
                for path in _TWS_LINT_FILTER_PATH_LIST:
                    # if path in file.get('file'):
                    if re.search(path, file.get('file')):
                        _file_path_in_filter = True
                        break
                if _file_path_in_filter:
                    continue

                files += code_path + file.get('file') + ' '


    lines = []
    if files:
        cmd = 'python3 %s %s %s' % (lint_script, lint_configs, files)
        ret = TIMEOUT_SHELL_COMMAND(cmd, timeout=120,capture_output=True)

        if not ret[0] and ret[1]:
            for line in ret[1]:
                if (lint_version is None) or (lint_version == 'v0.2'): # twslint version为v0.2
                    if line[:code_root_path_length] == code_root_path:
                        lines.append(line[code_root_path_length:])
                    else:
                        lines.append(line)
                else:  # twslint version为v0.3,针对lint v0.3输出stdout信息，提取错误关键字
                    if LINT_ERROR_SHOW_KWORDS in line:
                        if line[1:code_root_path_length+1] == code_root_path:  #log行开头格式是:'[./xxx/xxx/]'
                            lines.append(line[code_root_path_length+1:])
                        else:
                            lines.append(line)

        lint_result_file_path = _guardInfo.GetWorkingPath() + tws_lint_result_filename
        if os.path.exists(lint_result_file_path):
            cmd = 'rm -rf %s' % (lint_result_file_path)
            TIMEOUT_SHELL_COMMAND(cmd)

        try:
            fd = open(lint_result_file_path, 'w', encoding='utf8')
            for line in lines:
                fd.write(line + '\n')
            fd.close()
        except Exception as e:
            LOG(LEVEL_WARN, 'Cannot open tws lint result file [{}], please check, [{}]'.format(lint_result_file_path, e))

    if not lines:
        review_comments = '[TWS_LINT] PASS  '
        _guardInfo.tws_lint_success = True
    else:
        review_comments = '[TWS_LINT] FAIL  \\\n\\\r'
        # http://192.168.29.22:8080/job/tws_guard_2/24/artifact/working/tws_lint_check_result.log
        review_comments += 'You can check the TWS_LINT log in {}artifact/{}{}'.format(
                            _guardInfo.jenkins_url, _WORKING_ROOT_DIR, tws_lint_result_filename)

    _guardInfo.NotifyReviewToGerrit(review_comments)


def _DoCppcheck():
    cppcheck_script = _TOOLS_PATH + 'cppcheck/cppcheck'
    reporthtml_script = _TOOLS_PATH + 'cppcheck/htmlreport/cppcheck-htmlreport'
    reporthtml_report_dir = "cppcheck_report"
    reporthtml_report_path = _WORKING_ROOT_PATH + reporthtml_report_dir + "/"
    cppcheck_outputfile = _WORKING_ROOT_PATH + 'cppcheck_result.xml'
    cppcheck_file_filter_attr = '--file-filter='
    cppcheck_file_filter = ''
    code_root_path = _guardInfo.GetCodeRootPath()
    code_root_path_length = len(code_root_path)
    cppcheck_path = ''
    for index in range(0, _guardInfo.GetGerritProjectCount()):
        gerrit_project_name = _guardInfo.GetGerritProjectInfo(index)
        if gerrit_project_name in _PROJECT_CONFIG_INFO.get(_guardInfo.GetProjectName()).get('cppcheck_project'):
            code_path = _guardInfo.GetCherrypickPathByGerryProjectName(gerrit_project_name)
            cppcheck_path += code_path + ' '
            for file in _guardInfo.GetGerritFileInfo(index):
                if file.get('file') == '/COMMIT_MSG':
                    continue
                if file.get("type") == "DELETED":
                    continue
                if file.get('file')[file.get('file').rfind('.') + 1:] not in ['c', 'cpp']:
                    continue
                # files += code_path + file.get('file') + ' '
                cppcheck_file_filter += cppcheck_file_filter_attr + code_path + file.get('file') + ' '

    #-DUNITCODESECTION -DMARSHAL_COMMON_TYPES_TABLE -DLOGGING_PRESERVE_MESSAGE_ENUM
    cppcheck_marco_def_filter = _PROJECT_CONFIG_INFO.get(_guardInfo.GetProjectName()).get('cppcheck_marco_def')
    LOG(LEVEL_INFO, f"cppcheck_marco_def_filter list:{cppcheck_marco_def_filter}")

    if cppcheck_file_filter:
        if os.path.exists(cppcheck_outputfile):
            cmd = 'rm %s' % (cppcheck_outputfile)
            TIMEOUT_SHELL_COMMAND(cmd)
        check_suppress = ""
        check_suppress += " " + "--suppress=unusedFunction"
        check_suppress += " " + "--suppress=missingInclude"
        check_suppress += " " + "--suppress=unmatchedSuppression"
        check_suppress += " " + "--suppress=unusedStructMember"
        check_suppress += " " + "--suppress=variableScope"
        check_suppress += " " + "--suppress=unreadVariable"
        check_suppress += " " + "--suppress=constParameter"
        check_suppress += " " + "--suppress=ConfigurationNotChecked"

        if cppcheck_marco_def_filter:
            check_suppress +=  " " + cppcheck_marco_def_filter

        cmd = '%s --force --enable=all %s  --xml --output-file=%s %s %s' % (
                cppcheck_script, check_suppress, cppcheck_outputfile, cppcheck_path, cppcheck_file_filter)
        LOG(LEVEL_INFO, f"cppcheck cmd1: {cmd}")
        TIMEOUT_SHELL_COMMAND(cmd, timeout=180)
        # run cppcheck cmd
        if os.path.exists(reporthtml_report_path):
            cmd = 'rm -rf %s' % (reporthtml_report_path)
        cmd = '%s --file=%s --report-dir=%s --source-dir=.' % (
                reporthtml_script,
                cppcheck_outputfile,
                reporthtml_report_path.rstrip('/'))
        LOG(LEVEL_INFO, f"cppcheck cmd2: {cmd}")
        TIMEOUT_SHELL_COMMAND(cmd, timeout=180)

        gerrit_msg = '[cppcheck] FAIL  '
        if os.path.exists(cppcheck_outputfile) and os.path.exists(reporthtml_report_path):
            zip_name = reporthtml_report_path.rstrip('/').split()[-1]
            cmd = 'zip -r %s.zip %s' % (zip_name, reporthtml_report_path)
            ret = TIMEOUT_SHELL_COMMAND(cmd, cwd=_guardInfo.GetWorkingPath())
            if ret[0]:
                LOG(LEVEL_WARN, 'Build zip file fail [{}]'.format(cmd))

            gerrit_msg = '[cppcheck] PASS  '
            _guardInfo.cppcheck_success = True
            xml_data = XMLET.parse(cppcheck_outputfile)
            root = xml_data.getroot()
            for child in root:
                length = len(child.getchildren()) if sys.version_info.minor < 9 else len(child)
                if child.tag == 'errors' and length > 0:
                    gerrit_msg = '[cppcheck] FAIL  '
                    _guardInfo.cppcheck_success = False
                    break
        else:
            gerrit_msg = '[cppcheck] FAIL  '
    else:
        gerrit_msg = '[cppcheck] PASS  '
        _guardInfo.cppcheck_success = True

    if 'FAIL' in gerrit_msg:
        gerrit_msg += '\\\n\\\r'
        # http://192.168.29.22:8080/job/tws_guard_2/24/artifact/working/cppcheck_report/index.html
        gerrit_url = '{}/artifact/{}{}/index.html'.format(_guardInfo.jenkins_url, _WORKING_ROOT_DIR, reporthtml_report_dir)
        gerrit_msg += 'You can check the cppcheck_report on\\\n\\\r{}\\\n\\\r'.format(gerrit_url)
        gerrit_url = '{}/artifact/{}{}.zip'.format(_guardInfo.jenkins_url, _WORKING_ROOT_DIR, reporthtml_report_dir)
        gerrit_msg += 'Or you can download report on\\\n\\\r{}'.format(gerrit_url)
    _guardInfo.NotifyReviewToGerrit(gerrit_msg)


def _DeleteCode(path):
    if os.path.exists(path):
        cmd = 'rm -rf %s' % (path)
        subprocess.run(cmd, shell=True, timeout=120, encoding='utf8')


# start checkspecialitems.
'''
针对O71项目:
波及性检查优化1,下面这个config.ini,一般这4个目录下需要同时修改;若只修改其中1个,则verify -1;
如果真的只需要修改某一个config.ini, 其他不需要修改的话, 研发需找se确认。se手动+1.(但是除了这个config.ini, 其他检查项应该是通过状态)
product/ts7252a/config.ini', 'product/ts7252a_16/config.ini',
product/ts7252a_xpan/config.ini', 'product/ts7252a_xpan_16/config.ini
'''
def _TS7252A_DEV_CheckSpecialItems():
    _NEED_CHECK_FILE_PATH_LIST = ['product/ts7252a/config.ini', 'product/ts7252a_16/config.ini',
                                   'product/ts7252a_xpan/config.ini', 'product/ts7252a_xpan_16/config.ini']
    _NEED_CHECK_PATH_NUM = len(_NEED_CHECK_FILE_PATH_LIST)
    _COMPARE_FILE_NAME = 'config.ini'
    files = []
    for index in range(0, _guardInfo.GetGerritProjectCount()):
        for file in _guardInfo.GetGerritFileInfo(index):
            if file.get('file') == '/COMMIT_MSG':
                continue
            if file.get("type") == "DELETED":
                continue
            if file.get('file')[file.get('file').rfind('/') + 1:] != _COMPARE_FILE_NAME:
                continue
            onefile = file.get('file')
            LOG(LEVEL_INFO, f"file name:{onefile}")
            files.append(onefile)
    review_msg = ''
    missing_filename_msg = ''
    prompt_modify_filelist = []
    for checkitem in _NEED_CHECK_FILE_PATH_LIST:
        if checkitem not in files:
            missing_filename_msg += f'{checkitem}, '
            prompt_modify_filelist.append(checkitem)
    lack_num = len(prompt_modify_filelist)
    if lack_num == 0: # 修改全部涉及目录的config.ini，没有缺少修改
        LOG(LEVEL_INFO, "fully modify <config.ini> ok!")
    elif lack_num == _NEED_CHECK_PATH_NUM: # 没有修改任何一个config.ini，不涉及修改
        LOG(LEVEL_INFO, "no modify <config.ini> in this time.")
    elif 0 < lack_num < _NEED_CHECK_PATH_NUM : # 只修改了config.ini部分目录，需提示并verified -1
        prompt_info = "---File:[config.ini]\\\n\\\rmodifying paths should include:\\\n\\\r[ts7252a, ts7252a_16, ts7252a_xpan, ts7252a_xpan_16], \\\n\\\rfound missing modifying paths:\\\n\\\r["
        review_msg = prompt_info + missing_filename_msg + " ].\\\n\\\rHere verified -1. Any doubts, pls confirm with SE."
        _guardInfo.NotifyReviewToGerrit(review_msg)
        LOG(LEVEL_ERROR, f"config.ini not modify completely, missing modification:[{missing_filename_msg}], please check it.")
    else: # 获取到修改config.ini数量值无效
        LOG(LEVEL_INFO, "lack_num value is invalid!!!")

def _CheckSpecialItems():
    try:
        if _guardInfo.GetProjectName() == 'TS7252A_DEV':
            _TS7252A_DEV_CheckSpecialItems()
    except Exception as e:
        LOG(LEVEL_WARN, f"check special items exception: {e}")
# end checkspecialitems.

_ROLLBACK_CHERRYPICK_CMD_TEMPLATE = 'git clean -df .; git reset --hard HEAD^'
def _RollbackCherryPick():
    for index in range( _guardInfo.GetGerritProjectCount()):
        rollback_cherrypick_path = _guardInfo.GetCherrypickPathByGerryProjectName(_guardInfo.GetGerritProjectInfo(index))
        LOG(LEVEL_INFO, f"rollback cherrypick path:{rollback_cherrypick_path}")
        rollback_cherrypick_cmd = _ROLLBACK_CHERRYPICK_CMD_TEMPLATE
        ret = TIMEOUT_SHELL_COMMAND(rollback_cherrypick_cmd, timeout=120, cwd=rollback_cherrypick_path)
        if ret[0]:
            gerrit_msg = '[Patch Build] Rollback Cherry-pick Fail'
            _guardInfo.NotifyReviewToGerrit(gerrit_msg)
            LOG(LEVEL_ERROR, 'Rollback Cherry-pick fail: [{}] [{}]'.format(rollback_cherrypick_cmd, rollback_cherrypick_path))

def DoReview(res_check=True, lint_check=True):
    # step x: Init log env
    _LogInit(workdir=_guardInfo.GetWorkingPath(), codedir=_guardInfo.GetCodeRootPath(), guard_info_handle = _guardInfo)
    # step 1: set project work dir
    _InitReviewerWorkingEnv()
    # step 2: pull the project orginal code
    _PullProjectCode()
    _guardInfo.ParseProjectManifestInfo()
    # step 2.1: check special items.
    _CheckSpecialItems()
    # step 3: cherry pick the patch
    _CherrypickThePatch()
    # step 4: do tws lint check
    if lint_check:
        _DoTwsLintCheck()
    # step x: do cppcheck
    _DoCppcheck()

    if not _guardInfo.tws_lint_success or not _guardInfo.cppcheck_success:
        # exit('tws_lint or cppcheck fail')
        LOG(LEVEL_ERROR, f"\n{'-'*100}\nReview [Failed]: tws_lint [{_guardInfo.tws_lint_success}], cppcheck [{_guardInfo.cppcheck_success}]\n{'-'*100}\n")

    #step 5: rollback cherry-pick the patch to preview status.
    _RollbackCherryPick()
    # step 6: build the orginal code and save the output file
    _BuildEarphone(_guardInfo.GetImagePath('earbud', 'org'))

     # step 7: cherry pick the patch
    _CherrypickThePatch()
    # step 8: build the patch and save the output file
    _BuildEarphone(_guardInfo.GetImagePath('earbud', 'patch'))
    # step 9: do resource check
    if res_check:
        _DoResourceCheck()
    # step 10: build related project
    _build_impact_project_earphone()
    # step 11: delete code
    _DeleteCode(_guardInfo.GetCodeRootPath())
    # step x: send gerrit review finished info
    # step x: exist with error status\
    if not _guardInfo.tws_lint_success or not _guardInfo.cppcheck_success or not _guardInfo.impact_build_success:
        # exit('tws_lint or cppcheck fail')
        LOG(LEVEL_ERROR, f"\n{'-'*100}\nReview [Failed]: tws_lint [{_guardInfo.tws_lint_success}], cppcheck [{_guardInfo.cppcheck_success}], impact_build [{_guardInfo.impact_build_success}]\n{'-'*100}\n")
    else:
        review_msg = ' Static check [Successful] at {}'.format(_guardInfo.jenkins_url)
        _guardInfo.NotifyReviewToGerrit(review_msg, review=" --verified 1")

def GuardInit(output_type='offline', account_id='', change_id='', project_name='', jenkins_url=''):
    _guardInfo.output_type = output_type
    _guardInfo.account_id = account_id
    _guardInfo.change_id = change_id
    if jenkins_url:
        _guardInfo.jenkins_url = jenkins_url
    _guardInfo._SetProjectName(project_name)
    _QueryGerritInfo()
    _guardInfo.NotifyReviewToGerrit(' Review Start At: {}'.format(_guardInfo.GetJenkinsUrl()))


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='')
    parser.add_argument('--type',
                        '-t',
                        required=True,
                        metavar='online|offline',
                        choices=['online', 'offline'],
                        help='Output the result to gerrit (online) or stdio (offline)')
    parser.add_argument('--account',
                        '-a',
                        required=True,
                        metavar='1010xxxxx',
                        help='The gerrit account ID set on the PC')
    parser.add_argument('--changeid',
                        '-c',
                        required=True,
                        metavar='ChangeID',
                        help='The gerrit change ID you want to check')
    parser.add_argument('--project',
                        '-p',
                        required=True,
                        metavar='ts6239|ts6351a|ts6569a|all',
                        help='The project name of the change, "all" for check all project we have')
    parser.add_argument('--jenkins_url',
                        '-u',
                        metavar='optional for jenkins url',
                        help='The jenkins url where this script runing')
    args = parser.parse_args()

    GuardInit(args.type, args.account, args.changeid, args.project, args.jenkins_url)
    DoReview()
